diff --git a/debian/patches/debian/powerpc-mkvmlinuz-support-powerpc.patch b/debian/patches/debian/powerpc-mkvmlinuz-support-powerpc.patch index 7ed4ba858..2a602414d 100644 --- a/debian/patches/debian/powerpc-mkvmlinuz-support-powerpc.patch +++ b/debian/patches/debian/powerpc-mkvmlinuz-support-powerpc.patch @@ -29,12 +29,12 @@ PHONY += $(BOOT_TARGETS) ---- linux-2.6.19/arch/powerpc/boot/Makefile.orig 2006-12-05 16:14:42.000000000 +0000 -+++ linux-2.6.19/arch/powerpc/boot/Makefile 2006-12-05 16:13:37.000000000 +0000 -@@ -176,3 +176,18 @@ - +--- linux-2.6.20-rc3/arch/powerpc/boot/Makefile.orig 2007-01-04 16:22:53.000000000 +0100 ++++ linux-2.6.20-rc3/arch/powerpc/boot/Makefile 2007-01-04 16:23:40.000000000 +0100 +@@ -186,3 +186,19 @@ clean-files += $(addprefix $(objtree)/, $(obj-boot) vmlinux.strip.gz) clean-files += $(addprefix $(objtree)/, $(obj-boot) vmlinux.bin.gz) + clean-files += $(image-) + +#----------------------------------------------------------- +# install mkvmlinuz support files @@ -48,5 +48,6 @@ + mkdir -p $(INSTALL_MKVMLINUZ) + $(call cmd,mkvmlinuz) + -+targets += mkvmlinuz_support_install ++targets += mkvmlinuz_support_install ++ + diff --git a/debian/patches/features/powerpc/efika/0001-Fix-compilation-issue-when-PPC_MPC52xx-and-PPC_MERGE-are-selected.diff b/debian/patches/features/powerpc/efika/0001-Fix-compilation-issue-when-PPC_MPC52xx-and-PPC_MERGE-are-selected.diff deleted file mode 100644 index e8eef7dbc..000000000 --- a/debian/patches/features/powerpc/efika/0001-Fix-compilation-issue-when-PPC_MPC52xx-and-PPC_MERGE-are-selected.diff +++ /dev/null @@ -1,26 +0,0 @@ -From 9f3ff0ffed7c1fc1dbf3c0628f1a22a20d0846ce Mon Sep 17 00:00:00 2001 -From: Nicolas DET -Date: Fri, 24 Nov 2006 12:40:48 +0100 -Subject: [PATCH] Fix compilation issue when PPC_MPC52xx and PPC_MERGE are selected - -Signed-off-by: Nicolas DET ---- - include/asm-ppc/io.h | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h -index a4c411b..8ed380c 100644 ---- a/include/asm-ppc/io.h -+++ b/include/asm-ppc/io.h -@@ -26,7 +26,7 @@ #define PREP_PCI_DRAM_OFFSET 0x80000000 - - #if defined(CONFIG_4xx) - #include --#elif defined(CONFIG_PPC_MPC52xx) -+#elif defined(CONFIG_PPC_MPC52xx) && !defined(CONFIG_PPC_MERGE) - #include - #elif defined(CONFIG_8xx) - #include --- -1.4.3.2 - diff --git a/debian/patches/features/powerpc/efika/0001-powerpc-Add-support-for-uevent-to-of_platform.txt b/debian/patches/features/powerpc/efika/0001-powerpc-Add-support-for-uevent-to-of_platform.txt deleted file mode 100644 index 367415dea..000000000 --- a/debian/patches/features/powerpc/efika/0001-powerpc-Add-support-for-uevent-to-of_platform.txt +++ /dev/null @@ -1,105 +0,0 @@ -From 6f004b2fa4f9b6e5692084f7301271503788c05c Mon Sep 17 00:00:00 2001 -From: Sylvain Munaut -Date: Sat, 9 Dec 2006 02:06:55 +0100 -Subject: [PATCH] powerpc: Add support for uevent to of_platform - -This adds a proper uevent handler to the of_platform bus. This -allows autoloading of modules (or at least should ;). -It's _heavily_ based on the macio counterpart. - -Signed-off-by: Sylvain Munaut ---- - arch/powerpc/kernel/of_platform.c | 70 +++++++++++++++++++++++++++++++++++++ - 1 files changed, 70 insertions(+), 0 deletions(-) - -diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c -index b3189d0..f000023 100644 ---- a/arch/powerpc/kernel/of_platform.c -+++ b/arch/powerpc/kernel/of_platform.c -@@ -73,6 +73,75 @@ static int of_platform_bus_match(struct - return of_match_device(matches, of_dev) != NULL; - } - -+static int of_platform_uevent(struct device *dev, char **envp, int num_envp, -+ char *buffer, int buffer_size) -+{ -+ struct of_device *of; -+ const char *compat; -+ char *compat2; -+ char compat_buf[128]; /* need to be size of 'compatible' */ -+ -+ int i = 0; -+ int length = 0, cplen, sl, seen = 0; -+ -+ if (!dev) -+ return -ENODEV; -+ -+ of = to_of_device(dev); -+ if (!of) -+ return -ENODEV; -+ -+ /* stuff we want to pass to /sbin/hotplug */ -+ if (add_uevent_var(envp, num_envp, &i, -+ buffer, buffer_size, &length, -+ "OF_NAME=%s", of->node->name)) -+ return -ENOMEM; -+ -+ if (add_uevent_var(envp, num_envp, &i, -+ buffer, buffer_size, &length, -+ "OF_TYPE=%s", of->node->type)) -+ return -ENOMEM; -+ -+ /* Since the compatible field can contain pretty much anything -+ * it's not really legal to split it out with commas. We split it -+ * up using a number of environment variables instead. */ -+ -+ compat = get_property(of->node, "compatible", &cplen); -+ compat2 = compat_buf; -+ if (compat) -+ memcpy(compat2, compat, cplen); -+ while (compat && *compat && cplen > 0) { -+ if (add_uevent_var(envp, num_envp, &i, -+ buffer, buffer_size, &length, -+ "OF_COMPATIBLE_%d=%s", seen, compat)) -+ return -ENOMEM; -+ -+ sl = strlen (compat) + 1; -+ compat += sl; -+ compat2 += sl; -+ cplen -= sl; -+ seen++; -+ compat2[-1] = 'C'; -+ } -+ compat2[seen?-1:0] = 0; -+ -+ if (add_uevent_var(envp, num_envp, &i, -+ buffer, buffer_size, &length, -+ "OF_COMPATIBLE_N=%d", seen)) -+ return -ENOMEM; -+ -+ if (add_uevent_var(envp, num_envp, &i, -+ buffer, buffer_size, &length, -+ "MODALIAS=of:N%sT%sC%s", -+ of->node->name, of->node->type, -+ compat_buf)) -+ return -ENOMEM; -+ -+ envp[i] = NULL; -+ -+ return 0; -+} -+ - static int of_platform_device_probe(struct device *dev) - { - int error = -ENODEV; -@@ -132,6 +201,7 @@ static int of_platform_device_resume(str - struct bus_type of_platform_bus_type = { - .name = "of_platform", - .match = of_platform_bus_match, -+ .uevent = of_platform_uevent, - .probe = of_platform_device_probe, - .remove = of_platform_device_remove, - .suspend = of_platform_device_suspend, --- -1.4.2 - diff --git a/debian/patches/features/powerpc/efika/0001-powerpc-serial-Dispose-irq-mapping-when-done-in-mpc52xx_serial.c.txt b/debian/patches/features/powerpc/efika/0001-powerpc-serial-Dispose-irq-mapping-when-done-in-mpc52xx_serial.c.txt new file mode 100644 index 000000000..ef3c42dc3 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0001-powerpc-serial-Dispose-irq-mapping-when-done-in-mpc52xx_serial.c.txt @@ -0,0 +1,27 @@ +From 733239db928c98f4d110fc33f0cf1278cf5385ef Mon Sep 17 00:00:00 2001 +From: Sylvain Munaut +Date: Mon, 18 Dec 2006 22:48:02 +0100 +Subject: [PATCH] [PATCH] powerpc/serial: Dispose irq mapping when done in mpc52xx_serial.c + +Signed-off-by: Sylvain Munaut +--- + drivers/serial/mpc52xx_uart.c | 3 +++ + 1 files changed, 3 insertions(+), 0 deletions(-) + +diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c +index 9d11a75..eef3b02 100644 +--- a/drivers/serial/mpc52xx_uart.c ++++ b/drivers/serial/mpc52xx_uart.c +@@ -997,6 +997,9 @@ mpc52xx_uart_of_remove(struct of_device *op) + if (port) + uart_remove_one_port(&mpc52xx_uart_driver, port); + ++ if (port->irq != NO_IRQ) ++ irq_dispose_mapping(port->irq); ++ + return 0; + } + +-- +1.4.4.2 + diff --git a/debian/patches/features/powerpc/efika/0002-powerpc-52xx-Don-t-use-device_initcall-to-probe-of_platform_bus.txt b/debian/patches/features/powerpc/efika/0002-powerpc-52xx-Don-t-use-device_initcall-to-probe-of_platform_bus.txt new file mode 100644 index 000000000..71b0217c4 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0002-powerpc-52xx-Don-t-use-device_initcall-to-probe-of_platform_bus.txt @@ -0,0 +1,68 @@ +From 1dbea513815ce823ccded38d5668bbae7416223f Mon Sep 17 00:00:00 2001 +From: Sylvain Munaut +Date: Thu, 21 Dec 2006 22:21:20 +0100 +Subject: [PATCH] [PATCH] powerpc: 52xx, Don't use device_initcall to probe of_platform_bus + +Using device_initcall makes it happen for every platform that +compiles this file in. This is really bad, for obvious reasons. + +Instead, we use the .init field of the machine description. If +the platform needs the hook to do something specific it can provides +its own function and call mpc52xx_declare_of_platform_devices from +there. If not, the mpc52xx_declare_of_platform_devices function can +directly be used as the init hook. + +Signed-off-by: Sylvain Munaut +--- + arch/powerpc/platforms/52xx/lite5200.c | 1 + + arch/powerpc/platforms/52xx/mpc52xx_common.c | 7 ++++--- + include/asm-powerpc/mpc52xx.h | 1 + + 3 files changed, 6 insertions(+), 3 deletions(-) + +diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c +index eaff71e..0f21bab 100644 +--- a/arch/powerpc/platforms/52xx/lite5200.c ++++ b/arch/powerpc/platforms/52xx/lite5200.c +@@ -153,6 +153,7 @@ define_machine(lite52xx) { + .name = "lite52xx", + .probe = lite52xx_probe, + .setup_arch = lite52xx_setup_arch, ++ .init = mpc52xx_declare_of_platform_devices, + .init_IRQ = mpc52xx_init_irq, + .get_irq = mpc52xx_get_irq, + .show_cpuinfo = lite52xx_show_cpuinfo, +diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c +index 8331ff4..cc40889 100644 +--- a/arch/powerpc/platforms/52xx/mpc52xx_common.c ++++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c +@@ -116,11 +116,12 @@ unmap_regs: + if (xlb) iounmap(xlb); + } + +-static int __init ++void __init + mpc52xx_declare_of_platform_devices(void) + { + /* Find every child of the SOC node and add it to of_platform */ +- return of_platform_bus_probe(NULL, NULL, NULL); ++ if (of_platform_bus_probe(NULL, NULL, NULL)) ++ printk(KERN_ERR __FILE__ ": " ++ "Error while probing of_platform bus\n"); + } + +-device_initcall(mpc52xx_declare_of_platform_devices); +diff --git a/include/asm-powerpc/mpc52xx.h b/include/asm-powerpc/mpc52xx.h +index 4a28a85..4560d72 100644 +--- a/include/asm-powerpc/mpc52xx.h ++++ b/include/asm-powerpc/mpc52xx.h +@@ -244,6 +244,7 @@ struct mpc52xx_cdm { + extern void __iomem * mpc52xx_find_and_map(const char *); + extern unsigned int mpc52xx_find_ipb_freq(struct device_node *node); + extern void mpc52xx_setup_cpu(void); ++extern void mpc52xx_declare_of_platform_devices(void); + + extern void mpc52xx_init_irq(void); + extern unsigned int mpc52xx_get_irq(void); +-- +1.4.4.2 + diff --git a/debian/patches/features/powerpc/efika/0003-Add-MPC5200-serial-driver.diff b/debian/patches/features/powerpc/efika/0003-Add-MPC5200-serial-driver.diff deleted file mode 100644 index 6779065bb..000000000 --- a/debian/patches/features/powerpc/efika/0003-Add-MPC5200-serial-driver.diff +++ /dev/null @@ -1,719 +0,0 @@ -From 0ac70faf67a7e5e3f24a841ace4658336f8f98df Mon Sep 17 00:00:00 2001 -From: Nicolas DET -Date: Fri, 24 Nov 2006 13:00:06 +0100 -Subject: [PATCH] Add MPC5200 serial driver - -Signed-off-by: Nicolas DET ---- - drivers/serial/mpc52xx_uart.c | 287 +++++++++++++++++++++++++---------------- - 1 files changed, 178 insertions(+), 109 deletions(-) - -diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c -index 4f80c5b..debcd7b 100644 ---- a/drivers/serial/mpc52xx_uart.c -+++ b/drivers/serial/mpc52xx_uart.c -@@ -1,6 +1,4 @@ - /* -- * drivers/serial/mpc52xx_uart.c -- * - * Driver for the PSC of the Freescale MPC52xx PSCs configured as UARTs. - * - * FIXME According to the usermanual the status bits in the status register -@@ -14,18 +12,18 @@ - * - * - * Maintainer : Sylvain Munaut -- * -+ * - * Some of the code has been inspired/copied from the 2.4 code written - * by Dale Farnsworth . -- * -+ * - * Copyright (C) 2004-2005 Sylvain Munaut - * Copyright (C) 2003 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. - */ -- -+ - /* Platform device Usage : - * - * Since PSCs can have multiple function, the correct driver for each one -@@ -44,7 +42,8 @@ - * will be mapped to. - */ - --#include -+#define DEBUG -+ - #include - #include - #include -@@ -53,6 +52,8 @@ #include - - #include - #include -+#include -+#include - - #include - #include -@@ -96,32 +97,43 @@ #else - #define uart_console(port) (0) - #endif - -+static struct of_device_id mpc52xx_uart_match[] = { -+ { -+ .type = "serial", -+ .compatible = "mpc52xx-psc-uart", -+ }, -+ { -+ .type = "serial", -+ .compatible = "mpc5200-psc", -+ }, -+ {}, -+}; - - /* ======================================================================== */ - /* UART operations */ - /* ======================================================================== */ - --static unsigned int -+static unsigned int - mpc52xx_uart_tx_empty(struct uart_port *port) - { - int status = in_be16(&PSC(port)->mpc52xx_psc_status); - return (status & MPC52xx_PSC_SR_TXEMP) ? TIOCSER_TEMT : 0; - } - --static void -+static void - mpc52xx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) - { - /* Not implemented */ - } - --static unsigned int -+static unsigned int - mpc52xx_uart_get_mctrl(struct uart_port *port) - { - /* Not implemented */ - return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; - } - --static void -+static void - mpc52xx_uart_stop_tx(struct uart_port *port) - { - /* port->lock taken by caller */ -@@ -129,7 +141,7 @@ mpc52xx_uart_stop_tx(struct uart_port *p - out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask); - } - --static void -+static void - mpc52xx_uart_start_tx(struct uart_port *port) - { - /* port->lock taken by caller */ -@@ -137,12 +149,12 @@ mpc52xx_uart_start_tx(struct uart_port * - out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask); - } - --static void -+static void - mpc52xx_uart_send_xchar(struct uart_port *port, char ch) - { - unsigned long flags; - spin_lock_irqsave(&port->lock, flags); -- -+ - port->x_char = ch; - if (ch) { - /* Make sure tx interrupts are on */ -@@ -150,7 +162,7 @@ mpc52xx_uart_send_xchar(struct uart_port - port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY; - out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask); - } -- -+ - spin_unlock_irqrestore(&port->lock, flags); - } - -@@ -178,7 +190,7 @@ mpc52xx_uart_break_ctl(struct uart_port - out_8(&PSC(port)->command,MPC52xx_PSC_START_BRK); - else - out_8(&PSC(port)->command,MPC52xx_PSC_STOP_BRK); -- -+ - spin_unlock_irqrestore(&port->lock, flags); - } - -@@ -197,11 +209,11 @@ mpc52xx_uart_startup(struct uart_port *p - /* Reset/activate the port, clear and enable interrupts */ - out_8(&psc->command,MPC52xx_PSC_RST_RX); - out_8(&psc->command,MPC52xx_PSC_RST_TX); -- -+ - out_be32(&psc->sicr,0); /* UART mode DCD ignored */ - - out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); /* /16 prescaler on */ -- -+ - out_8(&psc->rfcntl, 0x00); - out_be16(&psc->rfalarm, 0x1ff); - out_8(&psc->tfcntl, 0x07); -@@ -209,10 +221,10 @@ mpc52xx_uart_startup(struct uart_port *p - - port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY; - out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask); -- -+ - out_8(&psc->command,MPC52xx_PSC_TX_ENABLE); - out_8(&psc->command,MPC52xx_PSC_RX_ENABLE); -- -+ - return 0; - } - -@@ -220,19 +232,19 @@ static void - mpc52xx_uart_shutdown(struct uart_port *port) - { - struct mpc52xx_psc __iomem *psc = PSC(port); -- -+ - /* Shut down the port, interrupt and all */ - out_8(&psc->command,MPC52xx_PSC_RST_RX); - out_8(&psc->command,MPC52xx_PSC_RST_TX); -- -- port->read_status_mask = 0; -+ -+ port->read_status_mask = 0; - out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask); - - /* Release interrupt */ - free_irq(port->irq, port); - } - --static void -+static void - mpc52xx_uart_set_termios(struct uart_port *port, struct termios *new, - struct termios *old) - { -@@ -241,10 +253,10 @@ mpc52xx_uart_set_termios(struct uart_por - unsigned char mr1, mr2; - unsigned short ctr; - unsigned int j, baud, quot; -- -+ - /* Prepare what we're gonna write */ - mr1 = 0; -- -+ - switch (new->c_cflag & CSIZE) { - case CS5: mr1 |= MPC52xx_PSC_MODE_5_BITS; - break; -@@ -261,8 +273,8 @@ mpc52xx_uart_set_termios(struct uart_por - MPC52xx_PSC_MODE_PARODD : MPC52xx_PSC_MODE_PAREVEN; - } else - mr1 |= MPC52xx_PSC_MODE_PARNONE; -- -- -+ -+ - mr2 = 0; - - if (new->c_cflag & CSTOPB) -@@ -276,7 +288,7 @@ mpc52xx_uart_set_termios(struct uart_por - baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16); - quot = uart_get_divisor(port, baud); - ctr = quot & 0xffff; -- -+ - /* Get the lock */ - spin_lock_irqsave(&port->lock, flags); - -@@ -290,14 +302,14 @@ mpc52xx_uart_set_termios(struct uart_por - * boot for the console, all stuff is not yet ready to receive at that - * time and that just makes the kernel oops */ - /* while (j-- && mpc52xx_uart_int_rx_chars(port)); */ -- while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) && -+ while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) && - --j) - udelay(1); - - if (!j) - printk( KERN_ERR "mpc52xx_uart.c: " - "Unable to flush RX & TX fifos in-time in set_termios." -- "Some chars may have been lost.\n" ); -+ "Some chars may have been lost.\n" ); - - /* Reset the TX & RX */ - out_8(&psc->command,MPC52xx_PSC_RST_RX); -@@ -309,7 +321,7 @@ mpc52xx_uart_set_termios(struct uart_por - out_8(&psc->mode,mr2); - out_8(&psc->ctur,ctr >> 8); - out_8(&psc->ctlr,ctr & 0xff); -- -+ - /* Reenable TX & RX */ - out_8(&psc->command,MPC52xx_PSC_TX_ENABLE); - out_8(&psc->command,MPC52xx_PSC_RX_ENABLE); -@@ -332,7 +344,7 @@ mpc52xx_uart_release_port(struct uart_po - port->membase = NULL; - } - -- release_mem_region(port->mapbase, MPC52xx_PSC_SIZE); -+ release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc)); - } - - static int -@@ -341,12 +353,13 @@ mpc52xx_uart_request_port(struct uart_po - int err; - - if (port->flags & UPF_IOREMAP) /* Need to remap ? */ -- port->membase = ioremap(port->mapbase, MPC52xx_PSC_SIZE); -+ port->membase = ioremap(port->mapbase, -+ sizeof(struct mpc52xx_psc)); - - if (!port->membase) - return -EINVAL; - -- err = request_mem_region(port->mapbase, MPC52xx_PSC_SIZE, -+ err = request_mem_region(port->mapbase, sizeof(struct mpc52xx_psc), - "mpc52xx_psc_uart") != NULL ? 0 : -EBUSY; - - if (err && (port->flags & UPF_IOREMAP)) { -@@ -373,7 +386,7 @@ mpc52xx_uart_verify_port(struct uart_por - - if ( (ser->irq != port->irq) || - (ser->io_type != SERIAL_IO_MEM) || -- (ser->baud_base != port->uartclk) || -+ (ser->baud_base != port->uartclk) || - (ser->iomem_base != (void*)port->mapbase) || - (ser->hub6 != 0 ) ) - return -EINVAL; -@@ -404,11 +417,11 @@ static struct uart_ops mpc52xx_uart_ops - .verify_port = mpc52xx_uart_verify_port - }; - -- -+ - /* ======================================================================== */ - /* Interrupt handling */ - /* ======================================================================== */ -- -+ - static inline int - mpc52xx_uart_int_rx_chars(struct uart_port *port) - { -@@ -435,11 +448,11 @@ #endif - - flag = TTY_NORMAL; - port->icount.rx++; -- -+ - if ( status & (MPC52xx_PSC_SR_PE | - MPC52xx_PSC_SR_FE | - MPC52xx_PSC_SR_RB) ) { -- -+ - if (status & MPC52xx_PSC_SR_RB) { - flag = TTY_BREAK; - uart_handle_break(port); -@@ -464,7 +477,7 @@ #endif - } - - tty_flip_buffer_push(tty); -- -+ - return in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_RXRDY; - } - -@@ -509,25 +522,25 @@ mpc52xx_uart_int_tx_chars(struct uart_po - return 1; - } - --static irqreturn_t -+static irqreturn_t - mpc52xx_uart_int(int irq, void *dev_id) - { - struct uart_port *port = dev_id; - unsigned long pass = ISR_PASS_LIMIT; - unsigned int keepgoing; - unsigned short status; -- -+ - spin_lock(&port->lock); -- -+ - /* While we have stuff to do, we continue */ - do { - /* If we don't find anything to do, we stop */ -- keepgoing = 0; -- -+ keepgoing = 0; -+ - /* Read status */ - status = in_be16(&PSC(port)->mpc52xx_psc_isr); - status &= port->read_status_mask; -- -+ - /* Do we need to receive chars ? */ - /* For this RX interrupts must be on and some chars waiting */ - if ( status & MPC52xx_PSC_IMR_RXRDY ) -@@ -537,15 +550,15 @@ mpc52xx_uart_int(int irq, void *dev_id) - /* For this, TX must be ready and TX interrupt enabled */ - if ( status & MPC52xx_PSC_IMR_TXRDY ) - keepgoing |= mpc52xx_uart_int_tx_chars(port); -- -+ - /* Limit number of iteration */ - if ( !(--pass) ) - keepgoing = 0; - - } while (keepgoing); -- -+ - spin_unlock(&port->lock); -- -+ - return IRQ_HANDLED; - } - -@@ -563,13 +576,13 @@ mpc52xx_console_get_options(struct uart_ - struct mpc52xx_psc __iomem *psc = PSC(port); - unsigned char mr1; - -+ pr_debug("mpc52xx_console_get_options(port=%p)\n", port); - /* Read the mode registers */ - out_8(&psc->command,MPC52xx_PSC_SEL_MODE_REG_1); - mr1 = in_8(&psc->mode); -- -+ - /* CT{U,L}R are write-only ! */ -- *baud = __res.bi_baudrate ? -- __res.bi_baudrate : CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD; -+ *baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD; - - /* Parse them */ - switch (mr1 & MPC52xx_PSC_MODE_BITS_MASK) { -@@ -579,26 +592,26 @@ mpc52xx_console_get_options(struct uart_ - case MPC52xx_PSC_MODE_8_BITS: - default: *bits = 8; - } -- -+ - if (mr1 & MPC52xx_PSC_MODE_PARNONE) - *parity = 'n'; - else - *parity = mr1 & MPC52xx_PSC_MODE_PARODD ? 'o' : 'e'; - } - --static void -+static void - mpc52xx_console_write(struct console *co, const char *s, unsigned int count) - { - struct uart_port *port = &mpc52xx_uart_ports[co->index]; - struct mpc52xx_psc __iomem *psc = PSC(port); - unsigned int i, j; -- -+ - /* Disable interrupts */ - out_be16(&psc->mpc52xx_psc_imr, 0); - - /* Wait the TX buffer to be empty */ -- j = 5000000; /* Maximum wait */ -- while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) && -+ j = 5000000; /* Maximum wait */ -+ while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) && - --j) - udelay(1); - -@@ -606,14 +619,14 @@ mpc52xx_console_write(struct console *co - for (i = 0; i < count; i++, s++) { - /* Line return handling */ - if (*s == '\n') -- out_8(&psc->mpc52xx_psc_buffer_8, '\r'); -- -+ out_8(&psc->buffer.buffer_8, '\r'); -+ - /* Send the char */ -- out_8(&psc->mpc52xx_psc_buffer_8, *s); -+ out_8(&psc->buffer.buffer_8, *s); - - /* Wait the TX buffer to be empty */ -- j = 20000; /* Maximum wait */ -- while (!(in_be16(&psc->mpc52xx_psc_status) & -+ j = 20000; /* Maximum wait */ -+ while (!(in_be16(&psc->mpc52xx_psc_status) & - MPC52xx_PSC_SR_TXEMP) && --j) - udelay(1); - } -@@ -626,33 +639,77 @@ static int __init - mpc52xx_console_setup(struct console *co, char *options) - { - struct uart_port *port = &mpc52xx_uart_ports[co->index]; -+ struct device_node *np = NULL; -+ const struct of_device_id *dev_id = NULL; -+ struct device_node *np_idx; -+ const void *pp = NULL; -+ struct resource res; -+ int index = 0; -+ int ret; - - int baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - -- if (co->index < 0 || co->index >= MPC52xx_PSC_MAXNUM) -+ pr_debug("mpc52xx_console_setup co=%p, options=%s, index=%i\n", -+ co, options, co->index); -+ -+ for_each_node_by_type(np, "serial") -+ { -+ dev_id = of_match_node(mpc52xx_uart_match, np); -+ if (dev_id) -+ if (index++ == co->index) -+ break; -+ } -+ -+ if (!np) { -+ pr_debug("PSC%x not found in device tree\n", co->index); -+ return -EINVAL; -+ } -+ -+ /* Fetch register locations */ -+ if ((ret = of_address_to_resource(np, 0, &res)) != 0) { -+ pr_debug("Could not get resources for PSC%x\n", index); -+ return ret; -+ } -+ -+ /* Search for bus-frequency property in this node or a parent */ -+ np_idx = np; -+ while (np_idx) { -+ if ((pp = get_property(np_idx, "bus-frequency", NULL)) != NULL) -+ break; -+ np_idx = of_get_parent(np_idx); -+ } -+ if (!pp) { -+ pr_debug("Could not find bus-frequency property!\n"); - return -EINVAL; -- -+ } -+ - /* Basic port init. Needed since we use some uart_??? func before - * real init for early access */ - spin_lock_init(&port->lock); -- port->uartclk = __res.bi_ipbfreq / 2; /* Look at CTLR doc */ -+ port->uartclk = *(const u32*)pp / 2; - port->ops = &mpc52xx_uart_ops; -- port->mapbase = MPC52xx_PA(MPC52xx_PSCx_OFFSET(co->index+1)); -+ port->mapbase = res.start; -+ port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc)); -+ port->irq = irq_of_parse_and_map(np, 0); - -- /* We ioremap ourself */ -- port->membase = ioremap(port->mapbase, MPC52xx_PSC_SIZE); - if (port->membase == NULL) - return -EINVAL; - -+ pr_debug("mpc52xx_psc at %lx mapped to %p; irq=%x freq=%i\n", -+ port->mapbase, port->membase, port->irq, port->uartclk); -+ - /* Setup the port parameters accoding to options */ - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - else - mpc52xx_console_get_options(port, &baud, &parity, &bits, &flow); - -+ pr_debug("Setting console parameters: %i %i%c1 flow=%c\n", -+ baud, bits, parity, flow); -+ - return uart_set_options(port, co, baud, parity, bits, flow); - } - -@@ -669,8 +726,8 @@ static struct console mpc52xx_console = - .data = &mpc52xx_uart_driver, - }; - -- --static int __init -+ -+static int __init - mpc52xx_console_init(void) - { - register_console(&mpc52xx_console); -@@ -705,28 +762,23 @@ static struct uart_driver mpc52xx_uart_d - /* ======================================================================== */ - - static int __devinit --mpc52xx_uart_probe(struct platform_device *dev) -+mpc52xx_uart_probe(struct of_device *op, const struct of_device_id *match) - { -- struct resource *res = dev->resource; -- -+ static int idx = 0; - struct uart_port *port = NULL; -- int i, idx, ret; -+ struct resource res; -+ int ret; -+ -+ dev_dbg(&op->dev, "mpc52xx_uart_probe(op=%p, match=%p)\n", op, match); - - /* Check validity & presence */ -- idx = dev->id; -- if (idx < 0 || idx >= MPC52xx_PSC_MAXNUM) -+ if (idx >= MPC52xx_PSC_MAXNUM) - return -EINVAL; - -- if (!mpc52xx_match_psc_function(idx,"uart")) -- return -ENODEV; -- - /* Init the port structure */ - port = &mpc52xx_uart_ports[idx]; - -- memset(port, 0x00, sizeof(struct uart_port)); -- - spin_lock_init(&port->lock); -- port->uartclk = __res.bi_ipbfreq / 2; /* Look at CTLR doc */ - port->fifosize = 512; - port->iotype = UPIO_MEM; - port->flags = UPF_BOOT_AUTOCONF | -@@ -735,29 +787,36 @@ mpc52xx_uart_probe(struct platform_devic - port->ops = &mpc52xx_uart_ops; - - /* Search for IRQ and mapbase */ -- for (i=0 ; inum_resources ; i++, res++) { -- if (res->flags & IORESOURCE_MEM) -- port->mapbase = res->start; -- else if (res->flags & IORESOURCE_IRQ) -- port->irq = res->start; -- } -- if (!port->irq || !port->mapbase) -+ if ((ret = of_address_to_resource(op->node, 0, &res)) != 0) -+ return ret; -+ -+ port->mapbase = res.start; -+ port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc)); -+ port->irq = irq_of_parse_and_map(op->node, 0); -+ -+ dev_dbg(&op->dev, "mpc52xx-psc UART at %lx. mapped to %p, irq %x\n", -+ port->mapbase, port->membase, port->irq); -+ -+ //if (!port->irq || !port->mapbase) { -+ if (!port->mapbase) { -+ printk(KERN_ERR "Could not allocate resources for PSC\n"); - return -EINVAL; -+ } - - /* Add the port to the uart sub-system */ - ret = uart_add_one_port(&mpc52xx_uart_driver, port); - if (!ret) -- platform_set_drvdata(dev, (void*)port); -+ dev_set_drvdata(&op->dev, (void*)port); - -+ idx++; - return ret; - } - - static int --mpc52xx_uart_remove(struct platform_device *dev) -+mpc52xx_uart_remove(struct of_device *op) - { -- struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev); -- -- platform_set_drvdata(dev, NULL); -+ struct uart_port *port = dev_get_drvdata(&op->dev); -+ dev_set_drvdata(&op->dev, NULL); - - if (port) - uart_remove_one_port(&mpc52xx_uart_driver, port); -@@ -767,20 +826,20 @@ mpc52xx_uart_remove(struct platform_devi - - #ifdef CONFIG_PM - static int --mpc52xx_uart_suspend(struct platform_device *dev, pm_message_t state) -+mpc52xx_uart_suspend(struct of_device *op, pm_message_t state) - { -- struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev); -+ struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev); - -- if (sport) -+ if (port) - uart_suspend_port(&mpc52xx_uart_driver, port); - - return 0; - } - - static int --mpc52xx_uart_resume(struct platform_device *dev) -+mpc52xx_uart_resume(struct of_device *op) - { -- struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev); -+ struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev); - - if (port) - uart_resume_port(&mpc52xx_uart_driver, port); -@@ -789,7 +848,13 @@ mpc52xx_uart_resume(struct platform_devi - } - #endif - --static struct platform_driver mpc52xx_uart_platform_driver = { -+ -+MODULE_DEVICE_TABLE(of, mpc52xx_uart_match); -+ -+static struct of_platform_driver mpc52xx_uart_of_driver = { -+ .owner = THIS_MODULE, -+ .name = "mpc52xx-uart", -+ .match_table = mpc52xx_uart_match, - .probe = mpc52xx_uart_probe, - .remove = mpc52xx_uart_remove, - #ifdef CONFIG_PM -@@ -804,7 +869,7 @@ #endif - - /* ======================================================================== */ - /* Module */ --/* ======================================================================== */ -+ /* ======================================================================== */ - - static int __init - mpc52xx_uart_init(void) -@@ -813,20 +878,24 @@ mpc52xx_uart_init(void) - - printk(KERN_INFO "Serial: MPC52xx PSC driver\n"); - -- ret = uart_register_driver(&mpc52xx_uart_driver); -- if (ret == 0) { -- ret = platform_driver_register(&mpc52xx_uart_platform_driver); -- if (ret) -- uart_unregister_driver(&mpc52xx_uart_driver); -+ if ((ret = uart_register_driver(&mpc52xx_uart_driver)) != 0) { -+ printk(KERN_ERR "Could not register mpc52xx uart driver\n"); -+ return ret; - } - -- return ret; -+ if ((ret = of_register_platform_driver(&mpc52xx_uart_of_driver)) != 0) { -+ printk(KERN_ERR "Could not register mpc52xx of driver\n"); -+ uart_unregister_driver(&mpc52xx_uart_driver); -+ return ret; -+ } -+ -+ return 0; - } - - static void __exit - mpc52xx_uart_exit(void) - { -- platform_driver_unregister(&mpc52xx_uart_platform_driver); -+ of_unregister_platform_driver(&mpc52xx_uart_of_driver); - uart_unregister_driver(&mpc52xx_uart_driver); - } - --- -1.4.3.2 - diff --git a/debian/patches/features/powerpc/efika/0004-powerpc-Use-common-52xx-of_platform-probe-code-for-EFIKA.txt b/debian/patches/features/powerpc/efika/0004-powerpc-Use-common-52xx-of_platform-probe-code-for-EFIKA.txt new file mode 100644 index 000000000..763d53208 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0004-powerpc-Use-common-52xx-of_platform-probe-code-for-EFIKA.txt @@ -0,0 +1,106 @@ +From ae911446f91481cf26e6dc5edef034a50a6c410c Mon Sep 17 00:00:00 2001 +From: Sylvain Munaut +Date: Sat, 23 Dec 2006 20:33:30 +0100 +Subject: [PATCH] [PATCH] powerpc: Use common 52xx of_platform probe code for EFIKA + +Now that the device tree has the good properties, we can +remove all the efika_init code by a single call to common code. + +While we're modifying that file, a few whitespaces/alignement/typo +fixes are made (nothing significant). + +Signed-off-by: Sylvain Munaut +--- + arch/powerpc/platforms/52xx/efika-setup.c | 64 ++++++++--------------------- + 1 files changed, 18 insertions(+), 46 deletions(-) + +diff --git a/arch/powerpc/platforms/52xx/efika-setup.c b/arch/powerpc/platforms/52xx/efika-setup.c +index 110c980..d61ce84 100644 +--- a/arch/powerpc/platforms/52xx/efika-setup.c ++++ b/arch/powerpc/platforms/52xx/efika-setup.c +@@ -2,7 +2,7 @@ + * + * Efika 5K2 platform setup + * Some code really inspired from the lite5200b platform. +- * ++ * + * Copyright (C) 2006 bplan GmbH + * + * This file is licensed under the terms of the GNU General Public License +@@ -81,35 +81,7 @@ static void __init efika_setup_arch(void) + efika_pcisetup(); + + if (ppc_md.progress) +- ppc_md.progress("Linux/PPC " UTS_RELEASE " runnung on Efika ;-)\n", 0x0); +-} +- +-static void __init efika_init(void) +-{ +- struct device_node *np; +- struct device_node *cnp = NULL; +- const u32 *base; +- +- /* Find every child of the SOC node and add it to of_platform */ +- np = of_find_node_by_name(NULL, "builtin"); +- if (np) { +- char name[BUS_ID_SIZE]; +- while ((cnp = of_get_next_child(np, cnp))) { +- strcpy(name, cnp->name); +- +- base = get_property(cnp, "reg", NULL); +- if (base == NULL) +- continue; +- +- snprintf(name+strlen(name), BUS_ID_SIZE, "@%x", *base); +- of_platform_device_create(cnp, name, NULL); +- +- printk(KERN_INFO EFIKA_PLATFORM_NAME" : Added %s (type '%s' at '%s') to the known devices\n", name, cnp->type, cnp->full_name); +- } +- } +- +- if (ppc_md.progress) +- ppc_md.progress(" Have fun with your Efika! ", 0x7777); ++ ppc_md.progress("Linux/PPC " UTS_RELEASE " running on Efika ;-)\n", 0x0); + } + + static int __init efika_probe(void) +@@ -131,20 +103,20 @@ static int __init efika_probe(void) + + define_machine(efika) + { +- .name = EFIKA_PLATFORM_NAME, +- .probe = efika_probe, +- .setup_arch = efika_setup_arch, +- .init = efika_init, +- .show_cpuinfo = efika_show_cpuinfo, +- .init_IRQ = mpc52xx_init_irq, +- .get_irq = mpc52xx_get_irq, +- .restart = rtas_restart, +- .power_off = rtas_power_off, +- .halt = rtas_halt, +- .set_rtc_time = rtas_set_rtc_time, +- .get_rtc_time = rtas_get_rtc_time, +- .progress = rtas_progress, +- .get_boot_time = rtas_get_boot_time, +- .calibrate_decr = generic_calibrate_decr, +- .phys_mem_access_prot = pci_phys_mem_access_prot, ++ .name = EFIKA_PLATFORM_NAME, ++ .probe = efika_probe, ++ .setup_arch = efika_setup_arch, ++ .init = mpc52xx_declare_of_platform_devices, ++ .show_cpuinfo = efika_show_cpuinfo, ++ .init_IRQ = mpc52xx_init_irq, ++ .get_irq = mpc52xx_get_irq, ++ .restart = rtas_restart, ++ .power_off = rtas_power_off, ++ .halt = rtas_halt, ++ .set_rtc_time = rtas_set_rtc_time, ++ .get_rtc_time = rtas_get_rtc_time, ++ .progress = rtas_progress, ++ .get_boot_time = rtas_get_boot_time, ++ .calibrate_decr = generic_calibrate_decr, ++ .phys_mem_access_prot = pci_phys_mem_access_prot, + }; +-- +1.4.4.2 + diff --git a/debian/patches/features/powerpc/efika/0005-Add-MPC5200-specific-header.diff b/debian/patches/features/powerpc/efika/0005-Add-MPC5200-specific-header.diff deleted file mode 100644 index 692260837..000000000 --- a/debian/patches/features/powerpc/efika/0005-Add-MPC5200-specific-header.diff +++ /dev/null @@ -1,306 +0,0 @@ -From e63b95820892f44ac7eec431900378763a83ae9d Mon Sep 17 00:00:00 2001 -From: Nicolas DET -Date: Fri, 24 Nov 2006 13:05:34 +0100 -Subject: [PATCH] Add MPC5200 specific header - -Signed-off-by: Nicolas DET ---- - include/asm-powerpc/mpc52xx.h | 287 +++++++++++++++++++++++++++++++++++++++++ - 1 files changed, 287 insertions(+), 0 deletions(-) - -diff --git a/include/asm-powerpc/mpc52xx.h b/include/asm-powerpc/mpc52xx.h -new file mode 100644 -index 0000000..e9aa622 ---- /dev/null -+++ b/include/asm-powerpc/mpc52xx.h -@@ -0,0 +1,287 @@ -+/* -+ * Prototypes, etc. for the Freescale MPC52xx embedded cpu chips -+ * May need to be cleaned as the port goes on ... -+ * -+ * Copyright (C) 2004-2005 Sylvain Munaut -+ * Copyright (C) 2003 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. -+ */ -+ -+#ifndef __ASM_POWERPC_MPC52xx_H__ -+#define __ASM_POWERPC_MPC52xx_H__ -+ -+#ifndef __ASSEMBLY__ -+#include -+#include -+#endif /* __ASSEMBLY__ */ -+ -+ -+/* ======================================================================== */ -+/* HW IRQ mapping */ -+/* ======================================================================== */ -+ -+#define MPC52xx_IRQ_L1_CRIT (0) -+#define MPC52xx_IRQ_L1_MAIN (1) -+#define MPC52xx_IRQ_L1_PERP (2) -+#define MPC52xx_IRQ_L1_SDMA (3) -+ -+#define MPC52xx_IRQ_L1_OFFSET (6) -+#define MPC52xx_IRQ_L1_MASK (0xc0) -+ -+#define MPC52xx_IRQ_L2_OFFSET (0) -+#define MPC52xx_IRQ_L2_MASK (0x3f) -+ -+#define MPC52xx_IRQ_HIGHTESTHWIRQ (0xd0) -+ -+ -+/* ======================================================================== */ -+/* Structures mapping of some unit register set */ -+/* ======================================================================== */ -+ -+#ifndef __ASSEMBLY__ -+ -+/* Interrupt controller Register set */ -+struct mpc52xx_intr { -+ u32 per_mask; /* INTR + 0x00 */ -+ u32 per_pri1; /* INTR + 0x04 */ -+ u32 per_pri2; /* INTR + 0x08 */ -+ u32 per_pri3; /* INTR + 0x0c */ -+ u32 ctrl; /* INTR + 0x10 */ -+ u32 main_mask; /* INTR + 0x14 */ -+ u32 main_pri1; /* INTR + 0x18 */ -+ u32 main_pri2; /* INTR + 0x1c */ -+ u32 reserved1; /* INTR + 0x20 */ -+ u32 enc_status; /* INTR + 0x24 */ -+ u32 crit_status; /* INTR + 0x28 */ -+ u32 main_status; /* INTR + 0x2c */ -+ u32 per_status; /* INTR + 0x30 */ -+ u32 reserved2; /* INTR + 0x34 */ -+ u32 per_error; /* INTR + 0x38 */ -+}; -+ -+/* Memory Mapping Control */ -+struct mpc52xx_mmap_ctl { -+ u32 mbar; /* MMAP_CTRL + 0x00 */ -+ -+ u32 cs0_start; /* MMAP_CTRL + 0x04 */ -+ u32 cs0_stop; /* MMAP_CTRL + 0x08 */ -+ u32 cs1_start; /* MMAP_CTRL + 0x0c */ -+ u32 cs1_stop; /* MMAP_CTRL + 0x10 */ -+ u32 cs2_start; /* MMAP_CTRL + 0x14 */ -+ u32 cs2_stop; /* MMAP_CTRL + 0x18 */ -+ u32 cs3_start; /* MMAP_CTRL + 0x1c */ -+ u32 cs3_stop; /* MMAP_CTRL + 0x20 */ -+ u32 cs4_start; /* MMAP_CTRL + 0x24 */ -+ u32 cs4_stop; /* MMAP_CTRL + 0x28 */ -+ u32 cs5_start; /* MMAP_CTRL + 0x2c */ -+ u32 cs5_stop; /* MMAP_CTRL + 0x30 */ -+ -+ u32 sdram0; /* MMAP_CTRL + 0x34 */ -+ u32 sdram1; /* MMAP_CTRL + 0X38 */ -+ -+ u32 reserved[4]; /* MMAP_CTRL + 0x3c .. 0x48 */ -+ -+ u32 boot_start; /* MMAP_CTRL + 0x4c */ -+ u32 boot_stop; /* MMAP_CTRL + 0x50 */ -+ -+ u32 ipbi_ws_ctrl; /* MMAP_CTRL + 0x54 */ -+ -+ u32 cs6_start; /* MMAP_CTRL + 0x58 */ -+ u32 cs6_stop; /* MMAP_CTRL + 0x5c */ -+ u32 cs7_start; /* MMAP_CTRL + 0x60 */ -+ u32 cs7_stop; /* MMAP_CTRL + 0x64 */ -+}; -+ -+/* SDRAM control */ -+struct mpc52xx_sdram { -+ u32 mode; /* SDRAM + 0x00 */ -+ u32 ctrl; /* SDRAM + 0x04 */ -+ u32 config1; /* SDRAM + 0x08 */ -+ u32 config2; /* SDRAM + 0x0c */ -+}; -+ -+/* SDMA */ -+struct mpc52xx_sdma { -+ u32 taskBar; /* SDMA + 0x00 */ -+ u32 currentPointer; /* SDMA + 0x04 */ -+ u32 endPointer; /* SDMA + 0x08 */ -+ u32 variablePointer; /* SDMA + 0x0c */ -+ -+ u8 IntVect1; /* SDMA + 0x10 */ -+ u8 IntVect2; /* SDMA + 0x11 */ -+ u16 PtdCntrl; /* SDMA + 0x12 */ -+ -+ u32 IntPend; /* SDMA + 0x14 */ -+ u32 IntMask; /* SDMA + 0x18 */ -+ -+ u16 tcr[16]; /* SDMA + 0x1c .. 0x3a */ -+ -+ u8 ipr[32]; /* SDMA + 0x3c .. 0x5b */ -+ -+ u32 cReqSelect; /* SDMA + 0x5c */ -+ u32 task_size0; /* SDMA + 0x60 */ -+ u32 task_size1; /* SDMA + 0x64 */ -+ u32 MDEDebug; /* SDMA + 0x68 */ -+ u32 ADSDebug; /* SDMA + 0x6c */ -+ u32 Value1; /* SDMA + 0x70 */ -+ u32 Value2; /* SDMA + 0x74 */ -+ u32 Control; /* SDMA + 0x78 */ -+ u32 Status; /* SDMA + 0x7c */ -+ u32 PTDDebug; /* SDMA + 0x80 */ -+}; -+ -+/* GPT */ -+struct mpc52xx_gpt { -+ u32 mode; /* GPTx + 0x00 */ -+ u32 count; /* GPTx + 0x04 */ -+ u32 pwm; /* GPTx + 0x08 */ -+ u32 status; /* GPTx + 0X0c */ -+}; -+ -+/* GPIO */ -+struct mpc52xx_gpio { -+ u32 port_config; /* GPIO + 0x00 */ -+ u32 simple_gpioe; /* GPIO + 0x04 */ -+ u32 simple_ode; /* GPIO + 0x08 */ -+ u32 simple_ddr; /* GPIO + 0x0c */ -+ u32 simple_dvo; /* GPIO + 0x10 */ -+ u32 simple_ival; /* GPIO + 0x14 */ -+ u8 outo_gpioe; /* GPIO + 0x18 */ -+ u8 reserved1[3]; /* GPIO + 0x19 */ -+ u8 outo_dvo; /* GPIO + 0x1c */ -+ u8 reserved2[3]; /* GPIO + 0x1d */ -+ u8 sint_gpioe; /* GPIO + 0x20 */ -+ u8 reserved3[3]; /* GPIO + 0x21 */ -+ u8 sint_ode; /* GPIO + 0x24 */ -+ u8 reserved4[3]; /* GPIO + 0x25 */ -+ u8 sint_ddr; /* GPIO + 0x28 */ -+ u8 reserved5[3]; /* GPIO + 0x29 */ -+ u8 sint_dvo; /* GPIO + 0x2c */ -+ u8 reserved6[3]; /* GPIO + 0x2d */ -+ u8 sint_inten; /* GPIO + 0x30 */ -+ u8 reserved7[3]; /* GPIO + 0x31 */ -+ u16 sint_itype; /* GPIO + 0x34 */ -+ u16 reserved8; /* GPIO + 0x36 */ -+ u8 gpio_control; /* GPIO + 0x38 */ -+ u8 reserved9[3]; /* GPIO + 0x39 */ -+ u8 sint_istat; /* GPIO + 0x3c */ -+ u8 sint_ival; /* GPIO + 0x3d */ -+ u8 bus_errs; /* GPIO + 0x3e */ -+ u8 reserved10; /* GPIO + 0x3f */ -+}; -+ -+#define MPC52xx_GPIO_PSC_CONFIG_UART_WITHOUT_CD 4 -+#define MPC52xx_GPIO_PSC_CONFIG_UART_WITH_CD 5 -+#define MPC52xx_GPIO_PCI_DIS (1<<15) -+ -+/* GPIO with WakeUp*/ -+struct mpc52xx_gpio_wkup { -+ u8 wkup_gpioe; /* GPIO_WKUP + 0x00 */ -+ u8 reserved1[3]; /* GPIO_WKUP + 0x03 */ -+ u8 wkup_ode; /* GPIO_WKUP + 0x04 */ -+ u8 reserved2[3]; /* GPIO_WKUP + 0x05 */ -+ u8 wkup_ddr; /* GPIO_WKUP + 0x08 */ -+ u8 reserved3[3]; /* GPIO_WKUP + 0x09 */ -+ u8 wkup_dvo; /* GPIO_WKUP + 0x0C */ -+ u8 reserved4[3]; /* GPIO_WKUP + 0x0D */ -+ u8 wkup_inten; /* GPIO_WKUP + 0x10 */ -+ u8 reserved5[3]; /* GPIO_WKUP + 0x11 */ -+ u8 wkup_iinten; /* GPIO_WKUP + 0x14 */ -+ u8 reserved6[3]; /* GPIO_WKUP + 0x15 */ -+ u16 wkup_itype; /* GPIO_WKUP + 0x18 */ -+ u8 reserved7[2]; /* GPIO_WKUP + 0x1A */ -+ u8 wkup_maste; /* GPIO_WKUP + 0x1C */ -+ u8 reserved8[3]; /* GPIO_WKUP + 0x1D */ -+ u8 wkup_ival; /* GPIO_WKUP + 0x20 */ -+ u8 reserved9[3]; /* GPIO_WKUP + 0x21 */ -+ u8 wkup_istat; /* GPIO_WKUP + 0x24 */ -+ u8 reserved10[3]; /* GPIO_WKUP + 0x25 */ -+}; -+ -+/* XLB Bus control */ -+struct mpc52xx_xlb { -+ u8 reserved[0x40]; -+ u32 config; /* XLB + 0x40 */ -+ u32 version; /* XLB + 0x44 */ -+ u32 status; /* XLB + 0x48 */ -+ u32 int_enable; /* XLB + 0x4c */ -+ u32 addr_capture; /* XLB + 0x50 */ -+ u32 bus_sig_capture; /* XLB + 0x54 */ -+ u32 addr_timeout; /* XLB + 0x58 */ -+ u32 data_timeout; /* XLB + 0x5c */ -+ u32 bus_act_timeout; /* XLB + 0x60 */ -+ u32 master_pri_enable; /* XLB + 0x64 */ -+ u32 master_priority; /* XLB + 0x68 */ -+ u32 base_address; /* XLB + 0x6c */ -+ u32 snoop_window; /* XLB + 0x70 */ -+}; -+ -+#define MPC52xx_XLB_CFG_PLDIS (1 << 31) -+#define MPC52xx_XLB_CFG_SNOOP (1 << 15) -+ -+/* Clock Distribution control */ -+struct mpc52xx_cdm { -+ u32 jtag_id; /* CDM + 0x00 reg0 read only */ -+ u32 rstcfg; /* CDM + 0x04 reg1 read only */ -+ u32 breadcrumb; /* CDM + 0x08 reg2 */ -+ -+ u8 mem_clk_sel; /* CDM + 0x0c reg3 byte0 */ -+ u8 xlb_clk_sel; /* CDM + 0x0d reg3 byte1 read only */ -+ u8 ipb_clk_sel; /* CDM + 0x0e reg3 byte2 */ -+ u8 pci_clk_sel; /* CDM + 0x0f reg3 byte3 */ -+ -+ u8 ext_48mhz_en; /* CDM + 0x10 reg4 byte0 */ -+ u8 fd_enable; /* CDM + 0x11 reg4 byte1 */ -+ u16 fd_counters; /* CDM + 0x12 reg4 byte2,3 */ -+ -+ u32 clk_enables; /* CDM + 0x14 reg5 */ -+ -+ u8 osc_disable; /* CDM + 0x18 reg6 byte0 */ -+ u8 reserved0[3]; /* CDM + 0x19 reg6 byte1,2,3 */ -+ -+ u8 ccs_sleep_enable; /* CDM + 0x1c reg7 byte0 */ -+ u8 osc_sleep_enable; /* CDM + 0x1d reg7 byte1 */ -+ u8 reserved1; /* CDM + 0x1e reg7 byte2 */ -+ u8 ccs_qreq_test; /* CDM + 0x1f reg7 byte3 */ -+ -+ u8 soft_reset; /* CDM + 0x20 u8 byte0 */ -+ u8 no_ckstp; /* CDM + 0x21 u8 byte0 */ -+ u8 reserved2[2]; /* CDM + 0x22 u8 byte1,2,3 */ -+ -+ u8 pll_lock; /* CDM + 0x24 reg9 byte0 */ -+ u8 pll_looselock; /* CDM + 0x25 reg9 byte1 */ -+ u8 pll_sm_lockwin; /* CDM + 0x26 reg9 byte2 */ -+ u8 reserved3; /* CDM + 0x27 reg9 byte3 */ -+ -+ u16 reserved4; /* CDM + 0x28 reg10 byte0,1 */ -+ u16 mclken_div_psc1; /* CDM + 0x2a reg10 byte2,3 */ -+ -+ u16 reserved5; /* CDM + 0x2c reg11 byte0,1 */ -+ u16 mclken_div_psc2; /* CDM + 0x2e reg11 byte2,3 */ -+ -+ u16 reserved6; /* CDM + 0x30 reg12 byte0,1 */ -+ u16 mclken_div_psc3; /* CDM + 0x32 reg12 byte2,3 */ -+ -+ u16 reserved7; /* CDM + 0x34 reg13 byte0,1 */ -+ u16 mclken_div_psc6; /* CDM + 0x36 reg13 byte2,3 */ -+}; -+ -+#endif /* __ASSEMBLY__ */ -+ -+ -+/* ========================================================================= */ -+/* Prototypes for MPC52xx sysdev */ -+/* ========================================================================= */ -+ -+#ifndef __ASSEMBLY__ -+ -+extern void mpc52xx_init_irq(void); -+extern unsigned int mpc52xx_get_irq(void); -+ -+#endif /* __ASSEMBLY__ */ -+ -+#endif /* __ASM_POWERPC_MPC52xx_H__ */ -+ --- -1.4.3.2 - diff --git a/debian/patches/features/powerpc/efika/0005-powerpc-Restore-proper-link-order-in-platform.txt b/debian/patches/features/powerpc/efika/0005-powerpc-Restore-proper-link-order-in-platform.txt new file mode 100644 index 000000000..0b4bbe337 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0005-powerpc-Restore-proper-link-order-in-platform.txt @@ -0,0 +1,33 @@ +From 720e2caeeff0d9585d5627d29ffd660a5a9d9f88 Mon Sep 17 00:00:00 2001 +From: Sylvain Munaut +Date: Sat, 23 Dec 2006 20:43:39 +0100 +Subject: [PATCH] [PATCH] powerpc: Restore 'proper' link order in platform + +The 52xx was put before CHRP to allow EFIKA to be recognized +properly. Now the efika tree is fixed up in prom_init so +no need for this ugly hack. So we restore the 'normal' +order. + +Signed-off-by: Sylvain Munaut +--- + arch/powerpc/platforms/Makefile | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile +index 507d1b9..44d95ea 100644 +--- a/arch/powerpc/platforms/Makefile ++++ b/arch/powerpc/platforms/Makefile +@@ -5,9 +5,9 @@ ifeq ($(CONFIG_PPC64),y) + obj-$(CONFIG_PPC_PMAC) += powermac/ + endif + endif +-obj-$(CONFIG_PPC_MPC52xx) += 52xx/ + obj-$(CONFIG_PPC_CHRP) += chrp/ + obj-$(CONFIG_4xx) += 4xx/ ++obj-$(CONFIG_PPC_MPC52xx) += 52xx/ + obj-$(CONFIG_PPC_83xx) += 83xx/ + obj-$(CONFIG_PPC_85xx) += 85xx/ + obj-$(CONFIG_PPC_86xx) += 86xx/ +-- +1.4.4.2 + diff --git a/debian/patches/features/powerpc/efika/0006-Add-MPC5200-interrupt-controller-driver.diff b/debian/patches/features/powerpc/efika/0006-Add-MPC5200-interrupt-controller-driver.diff deleted file mode 100644 index 113605c66..000000000 --- a/debian/patches/features/powerpc/efika/0006-Add-MPC5200-interrupt-controller-driver.diff +++ /dev/null @@ -1,570 +0,0 @@ -From b20c97e6f809bff52b864db1352a866c66a2bbd1 Mon Sep 17 00:00:00 2001 -From: Nicolas DET -Date: Fri, 24 Nov 2006 13:06:28 +0100 -Subject: [PATCH] Add MPC5200 interrupt controller driver - -Signed-off-by: Nicolas DET ---- - arch/powerpc/sysdev/Makefile | 1 + - arch/powerpc/sysdev/mpc52xx_pic.c | 538 +++++++++++++++++++++++++++++++++++++ - 2 files changed, 539 insertions(+), 0 deletions(-) - -diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile -index 91f052d..5b5b61e 100644 ---- a/arch/powerpc/sysdev/Makefile -+++ b/arch/powerpc/sysdev/Makefile -@@ -13,6 +13,7 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o - obj-$(CONFIG_PPC_TODC) += todc.o - obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o - obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ -+obj-$(CONFIG_PPC_MPC52xx) += mpc52xx_pic.o - - ifeq ($(CONFIG_PPC_MERGE),y) - obj-$(CONFIG_PPC_I8259) += i8259.o -diff --git a/arch/powerpc/sysdev/mpc52xx_pic.c b/arch/powerpc/sysdev/mpc52xx_pic.c -new file mode 100644 -index 0000000..6df51f0 ---- /dev/null -+++ b/arch/powerpc/sysdev/mpc52xx_pic.c -@@ -0,0 +1,538 @@ -+/* -+ * -+ * Programmable Interrupt Controller functions for the Freescale MPC52xx. -+ * -+ * Copyright (C) 2006 bplan GmbH -+ * -+ * Based on the code from the 2.4 kernel by -+ * Dale Farnsworth and Kent Borg. -+ * -+ * Copyright (C) 2004 Sylvain Munaut -+ * Copyright (C) 2003 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. -+ * -+ */ -+ -+#undef DEBUG -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * -+*/ -+ -+static struct mpc52xx_intr __iomem *intr; -+static struct mpc52xx_sdma __iomem *sdma; -+static struct irq_host *mpc52xx_irqhost = NULL; -+ -+static unsigned char mpc52xx_map_senses[4] = { -+ IRQ_TYPE_LEVEL_HIGH, -+ IRQ_TYPE_EDGE_RISING, -+ IRQ_TYPE_EDGE_FALLING, -+ IRQ_TYPE_LEVEL_LOW, -+}; -+ -+/* -+ * -+*/ -+ -+static inline void io_be_setbit(u32 __iomem * addr, int bitno) -+{ -+ out_be32(addr, in_be32(addr) | (1 << bitno)); -+} -+ -+static inline void io_be_clrbit(u32 __iomem * addr, int bitno) -+{ -+ out_be32(addr, in_be32(addr) & ~(1 << bitno)); -+} -+ -+/* -+ * IRQ[0-3] interrupt irq_chip -+*/ -+ -+static void mpc52xx_extirq_mask(unsigned int virq) -+{ -+ int irq; -+ int l2irq; -+ -+ irq = irq_map[virq].hwirq; -+ l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; -+ -+ pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); -+ -+ io_be_clrbit(&intr->ctrl, 11 - l2irq); -+} -+ -+static void mpc52xx_extirq_unmask(unsigned int virq) -+{ -+ int irq; -+ int l2irq; -+ -+ irq = irq_map[virq].hwirq; -+ l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; -+ -+ pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); -+ -+ io_be_setbit(&intr->ctrl, 11 - l2irq); -+} -+ -+static void mpc52xx_extirq_ack(unsigned int virq) -+{ -+ int irq; -+ int l2irq; -+ -+ irq = irq_map[virq].hwirq; -+ l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; -+ -+ pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); -+ -+ io_be_setbit(&intr->ctrl, 27 - l2irq); -+} -+ -+static struct irq_chip mpc52xx_extirq_irqchip = { -+ .typename = " MPC52xx IRQ[0-3] ", -+ .mask = mpc52xx_extirq_mask, -+ .unmask = mpc52xx_extirq_unmask, -+ .ack = mpc52xx_extirq_ack, -+}; -+ -+/* -+ * Main interrupt irq_chip -+*/ -+ -+static void mpc52xx_main_mask(unsigned int virq) -+{ -+ int irq; -+ int l2irq; -+ -+ irq = irq_map[virq].hwirq; -+ l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; -+ -+ pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); -+ -+ io_be_setbit(&intr->main_mask, 15 - l2irq); -+} -+ -+static void mpc52xx_main_unmask(unsigned int virq) -+{ -+ int irq; -+ int l2irq; -+ -+ irq = irq_map[virq].hwirq; -+ l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; -+ -+ pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); -+ -+ io_be_clrbit(&intr->main_mask, 15 - l2irq); -+} -+ -+static struct irq_chip mpc52xx_main_irqchip = { -+ .typename = "MPC52xx Main", -+ .mask = mpc52xx_main_mask, -+ .mask_ack = mpc52xx_main_mask, -+ .unmask = mpc52xx_main_unmask, -+}; -+ -+/* -+ * Peripherals interrupt irq_chip -+*/ -+ -+static void mpc52xx_periph_mask(unsigned int virq) -+{ -+ int irq; -+ int l2irq; -+ -+ irq = irq_map[virq].hwirq; -+ l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; -+ -+ pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); -+ -+ io_be_setbit(&intr->per_mask, 31 - l2irq); -+} -+ -+static void mpc52xx_periph_unmask(unsigned int virq) -+{ -+ int irq; -+ int l2irq; -+ -+ irq = irq_map[virq].hwirq; -+ l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; -+ -+ pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); -+ -+ io_be_clrbit(&intr->per_mask, 31 - l2irq); -+} -+ -+static struct irq_chip mpc52xx_periph_irqchip = { -+ .typename = "MPC52xx Peripherals", -+ .mask = mpc52xx_periph_mask, -+ .mask_ack = mpc52xx_periph_mask, -+ .unmask = mpc52xx_periph_unmask, -+}; -+ -+/* -+ * SDMA interrupt irq_chip -+*/ -+ -+static void mpc52xx_sdma_mask(unsigned int virq) -+{ -+ int irq; -+ int l2irq; -+ -+ irq = irq_map[virq].hwirq; -+ l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; -+ -+ pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); -+ -+ io_be_setbit(&sdma->IntMask, l2irq); -+} -+ -+static void mpc52xx_sdma_unmask(unsigned int virq) -+{ -+ int irq; -+ int l2irq; -+ -+ irq = irq_map[virq].hwirq; -+ l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; -+ -+ pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); -+ -+ io_be_clrbit(&sdma->IntMask, l2irq); -+} -+ -+static void mpc52xx_sdma_ack(unsigned int virq) -+{ -+ int irq; -+ int l2irq; -+ -+ irq = irq_map[virq].hwirq; -+ l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; -+ -+ pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); -+ -+ out_be32(&sdma->IntPend, 1 << l2irq); -+} -+ -+static struct irq_chip mpc52xx_sdma_irqchip = { -+ .typename = "MPC52xx SDMA", -+ .mask = mpc52xx_sdma_mask, -+ .unmask = mpc52xx_sdma_unmask, -+ .ack = mpc52xx_sdma_ack, -+}; -+ -+/* -+ * irq_host -+*/ -+ -+static int mpc52xx_irqhost_match(struct irq_host *h, struct device_node *node) -+{ -+ pr_debug("%s: node=%p\n", __func__, node); -+ return mpc52xx_irqhost->host_data == node; -+} -+ -+static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, -+ u32 * intspec, unsigned int intsize, -+ irq_hw_number_t * out_hwirq, -+ unsigned int *out_flags) -+{ -+ int intrvect_l1; -+ int intrvect_l2; -+ int intrvect_type; -+ int intrvect_linux; -+ -+ if (intsize != 3) -+ return -1; -+ -+ intrvect_l1 = (int)intspec[0]; -+ intrvect_l2 = (int)intspec[1]; -+ intrvect_type = (int)intspec[2]; -+ -+ intrvect_linux = -+ (intrvect_l1 << MPC52xx_IRQ_L1_OFFSET) & MPC52xx_IRQ_L1_MASK; -+ intrvect_linux |= -+ (intrvect_l2 << MPC52xx_IRQ_L2_OFFSET) & MPC52xx_IRQ_L2_MASK; -+ -+ pr_debug("return %x, l1=%d, l2=%d\n", intrvect_linux, intrvect_l1, -+ intrvect_l2); -+ -+ *out_hwirq = intrvect_linux; -+ *out_flags = mpc52xx_map_senses[intrvect_type]; -+ -+ return 0; -+} -+ -+/* -+ * this function retrieves the correct IRQ type out -+ * of the MPC regs -+ * Only externals IRQs needs this -+*/ -+static int mpc52xx_irqx_gettype(int irq) -+{ -+ int type; -+ u32 ctrl_reg; -+ -+ ctrl_reg = in_be32(&intr->ctrl); -+ type = (ctrl_reg >> (22 - irq * 2)) & 0x3; -+ -+ return mpc52xx_map_senses[type]; -+} -+ -+static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, -+ irq_hw_number_t irq) -+{ -+ int l1irq; -+ int l2irq; -+ struct irq_chip *good_irqchip; -+ void *good_handle; -+ int type; -+ -+ l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET; -+ l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; -+ -+ /* -+ * Most of ours IRQs will be level low -+ * Only external IRQs on some platform may be others -+ */ -+ type = IRQ_TYPE_LEVEL_LOW; -+ -+ switch (l1irq) { -+ case MPC52xx_IRQ_L1_CRIT: -+ pr_debug("%s: Critical. l2=%x\n", __func__, l2irq); -+ -+ BUG_ON(l2irq != 0); -+ -+ type = mpc52xx_irqx_gettype(l2irq); -+ good_irqchip = &mpc52xx_extirq_irqchip; -+ break; -+ -+ case MPC52xx_IRQ_L1_MAIN: -+ pr_debug("%s: Main IRQ[1-3] l2=%x\n", __func__, l2irq); -+ -+ if ((l2irq >= 1) && (l2irq <= 3)) { -+ type = mpc52xx_irqx_gettype(l2irq); -+ good_irqchip = &mpc52xx_extirq_irqchip; -+ } else { -+ good_irqchip = &mpc52xx_main_irqchip; -+ } -+ break; -+ -+ case MPC52xx_IRQ_L1_PERP: -+ pr_debug("%s: Peripherals. l2=%x\n", __func__, l2irq); -+ good_irqchip = &mpc52xx_periph_irqchip; -+ break; -+ -+ case MPC52xx_IRQ_L1_SDMA: -+ pr_debug("%s: SDMA. l2=%x\n", __func__, l2irq); -+ good_irqchip = &mpc52xx_sdma_irqchip; -+ break; -+ -+ default: -+ pr_debug("%s: Error, unknown L1 IRQ (0x%x)\n", __func__, l1irq); -+ printk(KERN_ERR "Unknow IRQ!\n"); -+ return -EINVAL; -+ } -+ -+ switch (type) { -+ case IRQ_TYPE_EDGE_FALLING: -+ case IRQ_TYPE_EDGE_RISING: -+ good_handle = handle_edge_irq; -+ break; -+ default: -+ good_handle = handle_level_irq; -+ } -+ -+ set_irq_chip_and_handler(virq, good_irqchip, good_handle); -+ -+ pr_debug("%s: virq=%x, hw=%x. type=%x\n", __func__, virq, -+ (int)irq, type); -+ -+ return 0; -+} -+ -+static struct irq_host_ops mpc52xx_irqhost_ops = { -+ .match = mpc52xx_irqhost_match, -+ .xlate = mpc52xx_irqhost_xlate, -+ .map = mpc52xx_irqhost_map, -+}; -+ -+/* -+ * init (public) -+*/ -+ -+void __init mpc52xx_init_irq(void) -+{ -+ struct device_node *picnode = NULL; -+ int picnode_regsize; -+ u32 picnode_regoffset; -+ -+ struct device_node *sdmanode = NULL; -+ int sdmanode_regsize; -+ u32 sdmanode_regoffset; -+ -+ u64 size64; -+ int flags; -+ -+ u32 intr_ctrl; -+ -+ picnode = of_find_compatible_node(NULL, "interrupt-controller", -+ "mpc5200-pic"); -+ if (picnode == NULL) { -+ printk(KERN_ERR "MPC52xx PIC: " -+ "Unable to find the interrupt controller " -+ "in the OpenFirmware device tree\n"); -+ goto end; -+ } -+ -+ sdmanode = of_find_compatible_node(NULL, "dma-controller", -+ "mpc5200-bestcomm"); -+ if (sdmanode == NULL) { -+ printk(KERN_ERR "MPC52xx PIC" -+ "Unable to find the Bestcomm DMA controller device " -+ "in the OpenFirmware device tree\n"); -+ goto end; -+ } -+ -+ /* Retrieve PIC ressources */ -+ picnode_regoffset = (u32) of_get_address(picnode, 0, &size64, &flags); -+ if (picnode_regoffset == 0) { -+ printk(KERN_ERR "MPC52xx PIC" -+ "Unable to get the interrupt controller address\n"); -+ goto end; -+ } -+ -+ picnode_regoffset = -+ of_translate_address(picnode, (u32 *) picnode_regoffset); -+ picnode_regsize = (int)size64; -+ -+ /* Retrieve SDMA ressources */ -+ sdmanode_regoffset = (u32) of_get_address(sdmanode, 0, &size64, &flags); -+ if (sdmanode_regoffset == 0) { -+ printk(KERN_ERR "MPC52xx PIC: " -+ "Unable to get the Bestcomm DMA controller address\n"); -+ goto end; -+ } -+ -+ sdmanode_regoffset = -+ of_translate_address(sdmanode, (u32 *) sdmanode_regoffset); -+ sdmanode_regsize = (int)size64; -+ -+ /* Remap the necessary zones */ -+ intr = ioremap(picnode_regoffset, picnode_regsize); -+ if (intr == NULL) { -+ printk(KERN_ERR "MPC52xx PIC: " -+ "Unable to ioremap interrupt controller registers!\n"); -+ goto end; -+ } -+ -+ sdma = ioremap(sdmanode_regoffset, sdmanode_regsize); -+ if (sdma == NULL) { -+ iounmap(intr); -+ printk(KERN_ERR "MPC52xx PIC: " -+ "Unable to ioremap Bestcomm DMA registers!\n"); -+ goto end; -+ } -+ -+ printk(KERN_INFO "MPC52xx PIC: MPC52xx PIC Remapped at 0x%8.8x\n", -+ picnode_regoffset); -+ printk(KERN_INFO "MPC52xx PIC: MPC52xx SDMA Remapped at 0x%8.8x\n", -+ sdmanode_regoffset); -+ -+ /* Disable all interrupt sources. */ -+ out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */ -+ out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */ -+ out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */ -+ out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */ -+ intr_ctrl = in_be32(&intr->ctrl); -+ intr_ctrl &= 0x00ff0000; /* Keeps IRQ[0-3] config */ -+ intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */ -+ 0x00001000 | /* MEE master external enable */ -+ 0x00000000 | /* 0 means disable IRQ 0-3 */ -+ 0x00000001; /* CEb route critical normally */ -+ out_be32(&intr->ctrl, intr_ctrl); -+ -+ /* Zero a bunch of the priority settings. */ -+ out_be32(&intr->per_pri1, 0); -+ out_be32(&intr->per_pri2, 0); -+ out_be32(&intr->per_pri3, 0); -+ out_be32(&intr->main_pri1, 0); -+ out_be32(&intr->main_pri2, 0); -+ -+ /* -+ * As last step, add an irq host to translate the real -+ * hw irq information provided by the ofw to linux virq -+ */ -+ -+ mpc52xx_irqhost = -+ irq_alloc_host(IRQ_HOST_MAP_LINEAR, MPC52xx_IRQ_HIGHTESTHWIRQ, -+ &mpc52xx_irqhost_ops, -1); -+ -+ if (mpc52xx_irqhost) { -+ mpc52xx_irqhost->host_data = picnode; -+ printk(KERN_INFO "MPC52xx PIC is up and running!\n"); -+ } else { -+ printk(KERN_ERR -+ "MPC52xx PIC: Unable to allocate the IRQ host\n"); -+ } -+ -+end: -+ of_node_put(picnode); -+ of_node_put(sdmanode); -+} -+ -+/* -+ * get_irq (public) -+*/ -+unsigned int mpc52xx_get_irq(void) -+{ -+ u32 status; -+ int irq = NO_IRQ_IGNORE; -+ -+ status = in_be32(&intr->enc_status); -+ if (status & 0x00000400) { /* critical */ -+ irq = (status >> 8) & 0x3; -+ if (irq == 2) /* high priority peripheral */ -+ goto peripheral; -+ irq |= (MPC52xx_IRQ_L1_CRIT << MPC52xx_IRQ_L1_OFFSET) & -+ MPC52xx_IRQ_L1_MASK; -+ } else if (status & 0x00200000) { /* main */ -+ irq = (status >> 16) & 0x1f; -+ if (irq == 4) /* low priority peripheral */ -+ goto peripheral; -+ irq |= (MPC52xx_IRQ_L1_MAIN << MPC52xx_IRQ_L1_OFFSET) & -+ MPC52xx_IRQ_L1_MASK; -+ } else if (status & 0x20000000) { /* peripheral */ -+ peripheral: -+ irq = (status >> 24) & 0x1f; -+ if (irq == 0) { /* bestcomm */ -+ status = in_be32(&sdma->IntPend); -+ irq = ffs(status) - 1; -+ irq |= (MPC52xx_IRQ_L1_SDMA << MPC52xx_IRQ_L1_OFFSET) & -+ MPC52xx_IRQ_L1_MASK; -+ } else -+ irq |= (MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET) & -+ MPC52xx_IRQ_L1_MASK; -+ } -+ -+ pr_debug("%s: irq=%x. virq=%d\n", __func__, irq, -+ irq_linear_revmap(mpc52xx_irqhost, irq)); -+ -+ return irq_linear_revmap(mpc52xx_irqhost, irq); -+} -+ --- -1.4.3.2 - diff --git a/debian/patches/features/powerpc/efika/0006-Rework-the-OHCI-quirk-mecanism-as-suggested-by-David.txt b/debian/patches/features/powerpc/efika/0006-Rework-the-OHCI-quirk-mecanism-as-suggested-by-David.txt new file mode 100644 index 000000000..39f6fef60 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0006-Rework-the-OHCI-quirk-mecanism-as-suggested-by-David.txt @@ -0,0 +1,236 @@ +From 9282a04f14cef512736ac4a895fb48456e6a8989 Mon Sep 17 00:00:00 2001 +From: Benjamin Herrenschmidt +Date: Thu, 14 Dec 2006 14:13:26 +1100 +Subject: [PATCH] [PATCH] Rework the OHCI quirk mecanism as suggested by David + +This patch applies David Brownell's suggestion for reworking the +OHCI quirk mechanism via a table of PCI IDs. It adapts the existing +quirks to use that mechanism. + +This also moves the quirks to reset() as suggested by the comment +in there. This is necessary as we need to have the endian properly +set before we try to init the controller. + +Signed-off-by: Benjamin Herrenschmidt +Acked-by: David Brownell + + drivers/usb/host/ohci-pci.c | 173 +++++++++++++++++++++++++++----------------- + 1 file changed, 110 insertions(+), 63 deletions(-) +--- + drivers/usb/host/ohci-pci.c | 173 +++++++++++++++++++++++++++---------------- + 1 files changed, 110 insertions(+), 63 deletions(-) + +diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c +index 596e0b4..82fbec3 100644 +--- a/drivers/usb/host/ohci-pci.c ++++ b/drivers/usb/host/ohci-pci.c +@@ -20,79 +20,128 @@ + + /*-------------------------------------------------------------------------*/ + +-static int +-ohci_pci_reset (struct usb_hcd *hcd) ++/* AMD 756, for most chips (early revs), corrupts register ++ * values on read ... so enable the vendor workaround. ++ */ ++static int __devinit ohci_quirk_amd756(struct usb_hcd *hcd) + { + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + +- ohci_hcd_init (ohci); +- return ohci_init (ohci); ++ ohci->flags = OHCI_QUIRK_AMD756; ++ ohci_dbg (ohci, "AMD756 erratum 4 workaround\n"); ++ ++ /* also erratum 10 (suspend/resume issues) */ ++ device_init_wakeup(&hcd->self.root_hub->dev, 0); ++ ++ return 0; + } + +-static int __devinit +-ohci_pci_start (struct usb_hcd *hcd) ++/* Apple's OHCI driver has a lot of bizarre workarounds ++ * for this chip. Evidently control and bulk lists ++ * can get confused. (B&W G3 models, and ...) ++ */ ++static int __devinit ohci_quirk_opti(struct usb_hcd *hcd) + { + struct ohci_hcd *ohci = hcd_to_ohci (hcd); +- int ret; + +- /* REVISIT this whole block should move to reset(), which handles +- * all the other one-time init. ++ ohci_dbg (ohci, "WARNING: OPTi workarounds unavailable\n"); ++ ++ return 0; ++} ++ ++/* Check for NSC87560. We have to look at the bridge (fn1) to ++ * identify the USB (fn2). This quirk might apply to more or ++ * even all NSC stuff. ++ */ ++static int __devinit ohci_quirk_ns(struct usb_hcd *hcd) ++{ ++ struct pci_dev *pdev = to_pci_dev(hcd->self.controller); ++ struct pci_dev *b; ++ ++ b = pci_get_slot (pdev->bus, PCI_DEVFN (PCI_SLOT (pdev->devfn), 1)); ++ if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO ++ && b->vendor == PCI_VENDOR_ID_NS) { ++ struct ohci_hcd *ohci = hcd_to_ohci (hcd); ++ ++ ohci->flags |= OHCI_QUIRK_SUPERIO; ++ ohci_dbg (ohci, "Using NSC SuperIO setup\n"); ++ } ++ pci_dev_put(b); ++ ++ return 0; ++} ++ ++/* Check for Compaq's ZFMicro chipset, which needs short ++ * delays before control or bulk queues get re-activated ++ * in finish_unlinks() ++ */ ++static int __devinit ohci_quirk_zfmicro(struct usb_hcd *hcd) ++{ ++ struct ohci_hcd *ohci = hcd_to_ohci (hcd); ++ ++ ohci->flags |= OHCI_QUIRK_ZFMICRO; ++ ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n"); ++ ++ return 0; ++} ++ ++ ++/* List of quirks for OHCI */ ++static const struct pci_device_id ohci_pci_quirks[] = { ++ { ++ PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x740c), ++ .driver_data = (unsigned long)ohci_quirk_amd756, ++ }, ++ { ++ PCI_DEVICE(PCI_VENDOR_ID_OPTI, 0xc861), ++ .driver_data = (unsigned long)ohci_quirk_opti, ++ }, ++ { ++ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_ANY_ID), ++ .driver_data = (unsigned long)ohci_quirk_ns, ++ }, ++ { ++ PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xa0f8), ++ .driver_data = (unsigned long)ohci_quirk_zfmicro, ++ }, ++ /* FIXME for some of the early AMD 760 southbridges, OHCI ++ * won't work at all. blacklist them. + */ ++ {}, ++}; ++ ++static int ohci_pci_reset (struct usb_hcd *hcd) ++{ ++ struct ohci_hcd *ohci = hcd_to_ohci (hcd); ++ int ret = 0; ++ + if (hcd->self.controller) { + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); ++ const struct pci_device_id *quirk_id; + +- /* AMD 756, for most chips (early revs), corrupts register +- * values on read ... so enable the vendor workaround. +- */ +- if (pdev->vendor == PCI_VENDOR_ID_AMD +- && pdev->device == 0x740c) { +- ohci->flags = OHCI_QUIRK_AMD756; +- ohci_dbg (ohci, "AMD756 erratum 4 workaround\n"); +- /* also erratum 10 (suspend/resume issues) */ +- device_init_wakeup(&hcd->self.root_hub->dev, 0); ++ quirk_id = pci_match_id(ohci_pci_quirks, pdev); ++ if (quirk_id != NULL) { ++ int (*quirk)(struct usb_hcd *ohci); ++ quirk = (void *)quirk_id->driver_data; ++ ret = quirk(hcd); + } ++ } ++ if (ret == 0) { ++ ohci_hcd_init (ohci); ++ return ohci_init (ohci); ++ } ++ return ret; ++} + +- /* FIXME for some of the early AMD 760 southbridges, OHCI +- * won't work at all. blacklist them. +- */ +- +- /* Apple's OHCI driver has a lot of bizarre workarounds +- * for this chip. Evidently control and bulk lists +- * can get confused. (B&W G3 models, and ...) +- */ +- else if (pdev->vendor == PCI_VENDOR_ID_OPTI +- && pdev->device == 0xc861) { +- ohci_dbg (ohci, +- "WARNING: OPTi workarounds unavailable\n"); +- } + +- /* Check for NSC87560. We have to look at the bridge (fn1) to +- * identify the USB (fn2). This quirk might apply to more or +- * even all NSC stuff. +- */ +- else if (pdev->vendor == PCI_VENDOR_ID_NS) { +- struct pci_dev *b; +- +- b = pci_get_slot (pdev->bus, +- PCI_DEVFN (PCI_SLOT (pdev->devfn), 1)); +- if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO +- && b->vendor == PCI_VENDOR_ID_NS) { +- ohci->flags |= OHCI_QUIRK_SUPERIO; +- ohci_dbg (ohci, "Using NSC SuperIO setup\n"); +- } +- pci_dev_put(b); +- } ++static int __devinit ohci_pci_start (struct usb_hcd *hcd) ++{ ++ struct ohci_hcd *ohci = hcd_to_ohci (hcd); ++ int ret; + +- /* Check for Compaq's ZFMicro chipset, which needs short +- * delays before control or bulk queues get re-activated +- * in finish_unlinks() +- */ +- else if (pdev->vendor == PCI_VENDOR_ID_COMPAQ +- && pdev->device == 0xa0f8) { +- ohci->flags |= OHCI_QUIRK_ZFMICRO; +- ohci_dbg (ohci, +- "enabled Compaq ZFMicro chipset quirk\n"); +- } ++#ifdef CONFIG_PM /* avoid warnings about unused pdev */ ++ if (hcd->self.controller) { ++ struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + + /* RWC may not be set for add-in PCI cards, since boot + * firmware probably ignored them. This transfers PCI +@@ -101,16 +150,14 @@ ohci_pci_start (struct usb_hcd *hcd) + if (device_may_wakeup(&pdev->dev)) + ohci->hc_control |= OHCI_CTRL_RWC; + } ++#endif /* CONFIG_PM */ + +- /* NOTE: there may have already been a first reset, to +- * keep bios/smm irqs from making trouble +- */ +- if ((ret = ohci_run (ohci)) < 0) { ++ ret = ohci_run (ohci); ++ if (ret < 0) { + ohci_err (ohci, "can't start\n"); + ohci_stop (hcd); +- return ret; + } +- return 0; ++ return ret; + } + + #ifdef CONFIG_PM +-- +1.4.4.2 + diff --git a/debian/patches/features/powerpc/efika/0007-Implement-support-for-split-endian-OHCI.txt b/debian/patches/features/powerpc/efika/0007-Implement-support-for-split-endian-OHCI.txt new file mode 100644 index 000000000..f49e0cfa7 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0007-Implement-support-for-split-endian-OHCI.txt @@ -0,0 +1,367 @@ +From a87f8738eb3651b7eea1feae793def3a48dc36c6 Mon Sep 17 00:00:00 2001 +From: Benjamin Herrenschmidt +Date: Thu, 14 Dec 2006 14:13:28 +1100 +Subject: [PATCH] [PATCH] Implement support for "split" endian OHCI + +This patch separates support for big endian MMIO register access +and big endian descriptors in order to support the Toshiba SCC +implementation which has big endian registers but little endian +in-memory descriptors. + +It simplifies the access functions a bit in ohci.h while at it. + +Signed-off-by: Benjamin Herrenschmidt +Acked-by: David Brownell + + drivers/usb/host/Kconfig | 10 ++ + drivers/usb/host/ohci-pci.c | 26 +++++++ + drivers/usb/host/ohci-ppc-soc.c | 2 + drivers/usb/host/ohci.h | 147 +++++++++++++++++++++++++--------------- + 4 files changed, 130 insertions(+), 55 deletions(-) +--- + drivers/usb/host/Kconfig | 10 ++- + drivers/usb/host/ohci-pci.c | 26 +++++++ + drivers/usb/host/ohci-ppc-soc.c | 2 +- + drivers/usb/host/ohci.h | 147 +++++++++++++++++++++++++-------------- + 4 files changed, 130 insertions(+), 55 deletions(-) + +diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig +index cc60759..faabce8 100644 +--- a/drivers/usb/host/Kconfig ++++ b/drivers/usb/host/Kconfig +@@ -101,7 +101,8 @@ config USB_OHCI_HCD_PPC_SOC + bool "OHCI support for on-chip PPC USB controller" + depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx) + default y +- select USB_OHCI_BIG_ENDIAN ++ select USB_OHCI_BIG_ENDIAN_DESC ++ select USB_OHCI_BIG_ENDIAN_MMIO + ---help--- + Enables support for the USB controller on the MPC52xx or + STB03xxx processor chip. If unsure, say Y. +@@ -115,7 +116,12 @@ config USB_OHCI_HCD_PCI + Enables support for PCI-bus plug-in USB controller cards. + If unsure, say Y. + +-config USB_OHCI_BIG_ENDIAN ++config USB_OHCI_BIG_ENDIAN_DESC ++ bool ++ depends on USB_OHCI_HCD ++ default n ++ ++config USB_OHCI_BIG_ENDIAN_MMIO + bool + depends on USB_OHCI_HCD + default n +diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c +index 82fbec3..292daf0 100644 +--- a/drivers/usb/host/ohci-pci.c ++++ b/drivers/usb/host/ohci-pci.c +@@ -85,6 +85,27 @@ static int __devinit ohci_quirk_zfmicro(struct usb_hcd *hcd) + return 0; + } + ++/* Check for Toshiba SCC OHCI which has big endian registers ++ * and little endian in memory data structures ++ */ ++static int __devinit ohci_quirk_toshiba_scc(struct usb_hcd *hcd) ++{ ++ struct ohci_hcd *ohci = hcd_to_ohci (hcd); ++ ++ /* That chip is only present in the southbridge of some ++ * cell based platforms which are supposed to select ++ * CONFIG_USB_OHCI_BIG_ENDIAN_MMIO. We verify here if ++ * that was the case though. ++ */ ++#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO ++ ohci->flags |= OHCI_QUIRK_BE_MMIO; ++ ohci_dbg (ohci, "enabled big endian Toshiba quirk\n"); ++ return 0; ++#else ++ ohci_err (ohci, "unsupported big endian Toshiba quirk\n"); ++ return -ENXIO; ++#endif ++} + + /* List of quirks for OHCI */ + static const struct pci_device_id ohci_pci_quirks[] = { +@@ -104,9 +125,14 @@ static const struct pci_device_id ohci_pci_quirks[] = { + PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xa0f8), + .driver_data = (unsigned long)ohci_quirk_zfmicro, + }, ++ { ++ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, 0x01b6), ++ .driver_data = (unsigned long)ohci_quirk_toshiba_scc, ++ }, + /* FIXME for some of the early AMD 760 southbridges, OHCI + * won't work at all. blacklist them. + */ ++ + {}, + }; + +diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c +index e1a7eb8..c7ce8e6 100644 +--- a/drivers/usb/host/ohci-ppc-soc.c ++++ b/drivers/usb/host/ohci-ppc-soc.c +@@ -72,7 +72,7 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver, + } + + ohci = hcd_to_ohci(hcd); +- ohci->flags |= OHCI_BIG_ENDIAN; ++ ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; + ohci_hcd_init(ohci); + + retval = usb_add_hcd(hcd, irq, IRQF_DISABLED); +diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h +index 405257f..fc7c161 100644 +--- a/drivers/usb/host/ohci.h ++++ b/drivers/usb/host/ohci.h +@@ -394,8 +394,9 @@ struct ohci_hcd { + #define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */ + #define OHCI_QUIRK_SUPERIO 0x02 /* natsemi */ + #define OHCI_QUIRK_INITRESET 0x04 /* SiS, OPTi, ... */ +-#define OHCI_BIG_ENDIAN 0x08 /* big endian HC */ +-#define OHCI_QUIRK_ZFMICRO 0x10 /* Compaq ZFMicro chipset*/ ++#define OHCI_QUIRK_BE_DESC 0x08 /* BE descriptors */ ++#define OHCI_QUIRK_BE_MMIO 0x10 /* BE registers */ ++#define OHCI_QUIRK_ZFMICRO 0x20 /* Compaq ZFMicro chipset*/ + // there are also chip quirks/bugs in init logic + + }; +@@ -439,117 +440,156 @@ static inline struct usb_hcd *ohci_to_hcd (const struct ohci_hcd *ohci) + * a minority (notably the IBM STB04XXX and the Motorola MPC5200 + * processors) implement them in big endian format. + * ++ * In addition some more exotic implementations like the Toshiba ++ * Spider (aka SCC) cell southbridge are "mixed" endian, that is, ++ * they have a different endianness for registers vs. in-memory ++ * descriptors. ++ * + * This attempts to support either format at compile time without a + * runtime penalty, or both formats with the additional overhead + * of checking a flag bit. ++ * ++ * That leads to some tricky Kconfig rules howevber. There are ++ * different defaults based on some arch/ppc platforms, though ++ * the basic rules are: ++ * ++ * Controller type Kconfig options needed ++ * --------------- ---------------------- ++ * little endian CONFIG_USB_OHCI_LITTLE_ENDIAN ++ * ++ * fully big endian CONFIG_USB_OHCI_BIG_ENDIAN_DESC _and_ ++ * CONFIG_USB_OHCI_BIG_ENDIAN_MMIO ++ * ++ * mixed endian CONFIG_USB_OHCI_LITTLE_ENDIAN _and_ ++ * CONFIG_USB_OHCI_BIG_ENDIAN_{MMIO,DESC} ++ * ++ * (If you have a mixed endian controller, you -must- also define ++ * CONFIG_USB_OHCI_LITTLE_ENDIAN or things will not work when building ++ * both your mixed endian and a fully big endian controller support in ++ * the same kernel image). + */ + +-#ifdef CONFIG_USB_OHCI_BIG_ENDIAN ++#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_DESC ++#ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN ++#define big_endian_desc(ohci) (ohci->flags & OHCI_QUIRK_BE_DESC) ++#else ++#define big_endian_desc(ohci) 1 /* only big endian */ ++#endif ++#else ++#define big_endian_desc(ohci) 0 /* only little endian */ ++#endif + ++#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO + #ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN +-#define big_endian(ohci) (ohci->flags & OHCI_BIG_ENDIAN) /* either */ ++#define big_endian_mmio(ohci) (ohci->flags & OHCI_QUIRK_BE_MMIO) ++#else ++#define big_endian_mmio(ohci) 1 /* only big endian */ ++#endif + #else +-#define big_endian(ohci) 1 /* only big endian */ ++#define big_endian_mmio(ohci) 0 /* only little endian */ + #endif + + /* + * Big-endian read/write functions are arch-specific. + * Other arches can be added if/when they're needed. ++ * ++ * REVISIT: arch/powerpc now has readl/writel_be, so the ++ * definition below can die once the STB04xxx support is ++ * finally ported over. + */ +-#if defined(CONFIG_PPC) ++#if defined(CONFIG_PPC) && !defined(CONFIG_PPC_MERGE) + #define readl_be(addr) in_be32((__force unsigned *)addr) + #define writel_be(val, addr) out_be32((__force unsigned *)addr, val) + #endif + +-static inline unsigned int ohci_readl (const struct ohci_hcd *ohci, +- __hc32 __iomem * regs) ++static inline unsigned int _ohci_readl (const struct ohci_hcd *ohci, ++ __hc32 __iomem * regs) + { +- return big_endian(ohci) ? readl_be (regs) : readl ((__force u32 *)regs); ++ return big_endian_mmio(ohci) ? ++ readl_be ((__force u32 *)regs) : ++ readl ((__force u32 *)regs); + } + +-static inline void ohci_writel (const struct ohci_hcd *ohci, +- const unsigned int val, __hc32 __iomem *regs) ++static inline void _ohci_writel (const struct ohci_hcd *ohci, ++ const unsigned int val, __hc32 __iomem *regs) + { +- big_endian(ohci) ? writel_be (val, regs) : +- writel (val, (__force u32 *)regs); ++ big_endian_mmio(ohci) ? ++ writel_be (val, (__force u32 *)regs) : ++ writel (val, (__force u32 *)regs); + } + +-#else /* !CONFIG_USB_OHCI_BIG_ENDIAN */ +- +-#define big_endian(ohci) 0 /* only little endian */ +- + #ifdef CONFIG_ARCH_LH7A404 +- /* Marc Singer: at the time this code was written, the LH7A404 +- * had a problem reading the USB host registers. This +- * implementation of the ohci_readl function performs the read +- * twice as a work-around. +- */ +-static inline unsigned int +-ohci_readl (const struct ohci_hcd *ohci, const __hc32 *regs) +-{ +- *(volatile __force unsigned int*) regs; +- return *(volatile __force unsigned int*) regs; +-} ++/* Marc Singer: at the time this code was written, the LH7A404 ++ * had a problem reading the USB host registers. This ++ * implementation of the ohci_readl function performs the read ++ * twice as a work-around. ++ */ ++#define ohci_readl(o,r) (_ohci_readl(o,r),_ohci_readl(o,r)) ++#define ohci_writel(o,v,r) _ohci_writel(o,v,r) + #else +- /* Standard version of ohci_readl uses standard, platform +- * specific implementation. */ +-static inline unsigned int +-ohci_readl (const struct ohci_hcd *ohci, __hc32 __iomem * regs) +-{ +- return readl(regs); +-} ++#define ohci_readl(o,r) _ohci_readl(o,r) ++#define ohci_writel(o,v,r) _ohci_writel(o,v,r) + #endif + +-static inline void ohci_writel (const struct ohci_hcd *ohci, +- const unsigned int val, __hc32 __iomem *regs) +-{ +- writel (val, regs); +-} +- +-#endif /* !CONFIG_USB_OHCI_BIG_ENDIAN */ + + /*-------------------------------------------------------------------------*/ + + /* cpu to ohci */ + static inline __hc16 cpu_to_hc16 (const struct ohci_hcd *ohci, const u16 x) + { +- return big_endian(ohci) ? (__force __hc16)cpu_to_be16(x) : (__force __hc16)cpu_to_le16(x); ++ return big_endian_desc(ohci) ? ++ (__force __hc16)cpu_to_be16(x) : ++ (__force __hc16)cpu_to_le16(x); + } + + static inline __hc16 cpu_to_hc16p (const struct ohci_hcd *ohci, const u16 *x) + { +- return big_endian(ohci) ? cpu_to_be16p(x) : cpu_to_le16p(x); ++ return big_endian_desc(ohci) ? ++ cpu_to_be16p(x) : ++ cpu_to_le16p(x); + } + + static inline __hc32 cpu_to_hc32 (const struct ohci_hcd *ohci, const u32 x) + { +- return big_endian(ohci) ? (__force __hc32)cpu_to_be32(x) : (__force __hc32)cpu_to_le32(x); ++ return big_endian_desc(ohci) ? ++ (__force __hc32)cpu_to_be32(x) : ++ (__force __hc32)cpu_to_le32(x); + } + + static inline __hc32 cpu_to_hc32p (const struct ohci_hcd *ohci, const u32 *x) + { +- return big_endian(ohci) ? cpu_to_be32p(x) : cpu_to_le32p(x); ++ return big_endian_desc(ohci) ? ++ cpu_to_be32p(x) : ++ cpu_to_le32p(x); + } + + /* ohci to cpu */ + static inline u16 hc16_to_cpu (const struct ohci_hcd *ohci, const __hc16 x) + { +- return big_endian(ohci) ? be16_to_cpu((__force __be16)x) : le16_to_cpu((__force __le16)x); ++ return big_endian_desc(ohci) ? ++ be16_to_cpu((__force __be16)x) : ++ le16_to_cpu((__force __le16)x); + } + + static inline u16 hc16_to_cpup (const struct ohci_hcd *ohci, const __hc16 *x) + { +- return big_endian(ohci) ? be16_to_cpup((__force __be16 *)x) : le16_to_cpup((__force __le16 *)x); ++ return big_endian_desc(ohci) ? ++ be16_to_cpup((__force __be16 *)x) : ++ le16_to_cpup((__force __le16 *)x); + } + + static inline u32 hc32_to_cpu (const struct ohci_hcd *ohci, const __hc32 x) + { +- return big_endian(ohci) ? be32_to_cpu((__force __be32)x) : le32_to_cpu((__force __le32)x); ++ return big_endian_desc(ohci) ? ++ be32_to_cpu((__force __be32)x) : ++ le32_to_cpu((__force __le32)x); + } + + static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x) + { +- return big_endian(ohci) ? be32_to_cpup((__force __be32 *)x) : le32_to_cpup((__force __le32 *)x); ++ return big_endian_desc(ohci) ? ++ be32_to_cpup((__force __be32 *)x) : ++ le32_to_cpup((__force __le32 *)x); + } + + /*-------------------------------------------------------------------------*/ +@@ -557,6 +597,9 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x) + /* HCCA frame number is 16 bits, but is accessed as 32 bits since not all + * hardware handles 16 bit reads. That creates a different confusion on + * some big-endian SOC implementations. Same thing happens with PSW access. ++ * ++ * FIXME: Deal with that as a runtime quirk when STB03xxx is ported over ++ * to arch/powerpc + */ + + #ifdef CONFIG_STB03xxx +@@ -568,7 +611,7 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x) + static inline u16 ohci_frame_no(const struct ohci_hcd *ohci) + { + u32 tmp; +- if (big_endian(ohci)) { ++ if (big_endian_desc(ohci)) { + tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no); + tmp >>= OHCI_BE_FRAME_NO_SHIFT; + } else +@@ -580,7 +623,7 @@ static inline u16 ohci_frame_no(const struct ohci_hcd *ohci) + static inline __hc16 *ohci_hwPSWp(const struct ohci_hcd *ohci, + const struct td *td, int index) + { +- return (__hc16 *)(big_endian(ohci) ? ++ return (__hc16 *)(big_endian_desc(ohci) ? + &td->hwPSW[index ^ 1] : &td->hwPSW[index]); + } + +-- +1.4.4.2 + diff --git a/debian/patches/features/powerpc/efika/0008-Add-MPC5200-SDMA-PIO-driver.diff b/debian/patches/features/powerpc/efika/0008-Add-MPC5200-SDMA-PIO-driver.diff deleted file mode 100644 index e398cba38..000000000 --- a/debian/patches/features/powerpc/efika/0008-Add-MPC5200-SDMA-PIO-driver.diff +++ /dev/null @@ -1,3973 +0,0 @@ -From e94e3e06dcf17bc739806a8a4cd8d732f7f45074 Mon Sep 17 00:00:00 2001 -From: Nicolas DET -Date: Fri, 24 Nov 2006 13:10:46 +0100 -Subject: [PATCH] Add MPC5200 SDMA/PIO driver - -Signed-off-by: Nicolas DET ---- - drivers/block/Kconfig | 25 + - drivers/block/Makefile | 1 + - drivers/block/mpc52xx/Makefile | 9 + - drivers/block/mpc52xx/ata.c | 216 +++++++ - drivers/block/mpc52xx/dodrivecmd.c | 138 ++++ - drivers/block/mpc52xx/hwmisc.c | 577 +++++++++++++++++ - drivers/block/mpc52xx/mpc52xx_blockata.h | 311 +++++++++ - drivers/block/mpc52xx/mpc52xx_ide.h | 131 ++++ - drivers/block/mpc52xx/piofunc_inline.h | 250 ++++++++ - drivers/block/mpc52xx/protos.h | 107 ++++ - drivers/block/mpc52xx/sdmatask.c | 142 ++++ - drivers/block/mpc52xx/skel.c | 1024 ++++++++++++++++++++++++++++++ - drivers/block/mpc52xx/transfer.c | 932 +++++++++++++++++++++++++++ - 13 files changed, 3863 insertions(+), 0 deletions(-) - -diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig -index 17dc222..0d9d9c1 100644 ---- a/drivers/block/Kconfig -+++ b/drivers/block/Kconfig -@@ -63,6 +63,31 @@ config AMIGA_Z2RAM - To compile this driver as a module, choose M here: the - module will be called z2ram. - -+config BLK_DEV_MPC52XX_ATAPIO -+ tristate "MPC52xx ATA/PIO support" -+ depends on PPC_EFIKA -+ help -+ Selects this one if you are running on Efika 5k2 -+ -+config BLK_DEV_MPC52XX_ATAPIO_SDMA -+ bool "Use DMA driven PIO transfert" -+ depends on BLK_DEV_MPC52XX_ATAPIO -+ help -+ take advantage of the Bestcom SDMA engine on the MPC52xx to transfer -+ data to and from the PIO Fifo. -+ This offload the CPU core and allow higher transfer rate. -+ -+config BLK_DEV_MPC52XX_ATAPIO_MAXPIO -+ bool "Probe and set up the best PIO mode when setting the drive up" -+ depends on BLK_DEV_MPC52XX_ATAPIO -+ help -+ Probe and set up the best PIO mode available for the drive on -+ driver startup -+ -+config BLK_DEV_MPC52XX_ATAPIO_VERBOSE -+ bool "Print out loads of verbose information" -+ depends on BLK_DEV_MPC52XX_ATAPIO -+ - config ATARI_ACSI - tristate "Atari ACSI support" - depends on ATARI && BROKEN -diff --git a/drivers/block/Makefile b/drivers/block/Makefile -index 410f259..72a5e66 100644 ---- a/drivers/block/Makefile -+++ b/drivers/block/Makefile -@@ -30,3 +30,4 @@ obj-$(CONFIG_VIODASD) += viodasd.o - obj-$(CONFIG_BLK_DEV_SX8) += sx8.o - obj-$(CONFIG_BLK_DEV_UB) += ub.o - -+obj-$(CONFIG_BLK_DEV_MPC52XX_ATAPIO) += mpc52xx/ -diff --git a/drivers/block/mpc52xx/Makefile b/drivers/block/mpc52xx/Makefile -new file mode 100644 -index 0000000..3f20c67 ---- /dev/null -+++ b/drivers/block/mpc52xx/Makefile -@@ -0,0 +1,9 @@ -+# -+# Makefile for the kernel block device drivers. -+# -+# 12 June 2000, Christoph Hellwig -+# Rewritten to use lists instead of if-statements. -+# -+ -+obj-$(CONFIG_BLK_DEV_MPC52XX_ATAPIO) += skel.o sdmatask.o ata.o transfer.o hwmisc.o dodrivecmd.o -+ -diff --git a/drivers/block/mpc52xx/ata.c b/drivers/block/mpc52xx/ata.c -new file mode 100644 -index 0000000..dced8b1 ---- /dev/null -+++ b/drivers/block/mpc52xx/ata.c -@@ -0,0 +1,216 @@ -+/* -+ * mpc52xx_atablock / ata.c -+ * -+ * Copyright 2006 bplan GmbH -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file "COPYING" in the main directory of this archive -+ * for more details. -+ */ -+ -+ -+/**************/ -+/**************/ -+/**************/ -+ -+#include "mpc52xx_blockata.h" -+ -+/**************/ -+/**************/ -+/**************/ -+int mpc52xx_ata_dodrivereset(struct mpc52xx_blockata_priv *priv) -+{ -+ int ret; -+ -+ write_cmd(priv, ATA_CMD_RESET); -+ -+ ret = wait_not_busy(priv); -+ if (ret<0) -+ return ret; -+ -+ if ( ATASTS_GOT_ERR(read_altstatus(priv)) ) -+ return -1; -+ -+ return mpc52xx_ata_doidentify(priv); -+} -+ -+ -+/**************/ -+int mpc52xx_ata_regcheck(struct mpc52xx_blockata_priv *priv) -+{ -+ u8 seccnt; -+ u8 sector; -+ -+ write_sectorcnt(priv, 0x55); -+ write_sectornum(priv, 0xaa); -+ write_sectorcnt(priv, 0xaa); -+ write_sectornum(priv, 0x55); -+ write_sectorcnt(priv, 0x55); -+ write_sectornum(priv, 0xaa); -+ -+ seccnt = read_sectorcnt(priv); -+ sector = read_sectornum(priv); -+ -+ NPRINTK("%s: seccnt=%x, sector=%x\n", __func__, seccnt, sector ); -+ -+ if -+ ( -+ ( (seccnt == 0x55) || (seccnt == 0x01) ) -+ && (sector == 0xaa) -+ ) -+ return 0; -+ -+ return -1; -+} -+ -+/**************/ -+/**************/ -+static int ata_docpupollread( -+ struct mpc52xx_blockata_priv *priv, -+ void *buffer, -+ int len) -+{ -+ u16 *buffer16 = (u16 *) buffer; -+ int local_len = len; -+ -+ while(local_len--) -+ *buffer16++ = read_data(priv); -+ -+ return len - local_len; -+} -+ -+/**************/ -+static int ata_docpupollwrite( -+ struct mpc52xx_blockata_priv *priv, -+ void *buffer, -+ int len) -+{ -+ u16 *buffer16 = (u16 *) buffer; -+ int local_len = len; -+ -+ while(local_len--) -+ write_data(priv, *buffer16++); -+ -+ return len - local_len; -+ -+} -+ -+ -+/**************/ -+int mpc52xx_ata_setupsector( -+ struct mpc52xx_blockata_priv *priv, -+ sector_t sector, -+ int sector_num, -+ int is_write) -+{ -+ u8 seccnt, secnum, cyl_lo, cyl_hi, devhead; -+ u16 cyl16; -+ -+ if (priv->drive_canlba) { -+ if ( sector & (0xfffff0000000LL) ) { -+ if (!priv->drive_canlba48) -+ return -1; -+ -+ write_sectornum(priv, (sector >> 24) & 0xff); -+ -+ write_cyllo(priv, (sector >> 32) & 0xff); -+ -+ write_cylhi(priv, (sector >> 40) & 0xff); -+ -+ write_sectorcnt(priv, sector_num & 0xff00); -+ sector_num &= 0xff; -+ -+ sector &= 0xffffff; -+ -+ if ( (priv->multi_available) && (sector_num > 1) ) -+ priv->curio_atacmd = is_write ? ATA_CMD_WRITE_MULTI_EXT : ATA_CMD_READ_MULTI_EXT; -+ else -+ priv->curio_atacmd = is_write ? ATA_CMD_PIO_WRITE_EXT : ATA_CMD_PIO_READ_EXT; -+ -+ } else { -+ if ( (priv->multi_available) && (sector_num > 1) ) -+ priv->curio_atacmd = is_write ? ATA_CMD_WRITE_MULTI : ATA_CMD_READ_MULTI; -+ else -+ priv->curio_atacmd = is_write ? ATA_CMD_PIO_WRITE : ATA_CMD_PIO_READ; -+ } -+ -+ secnum = sector & 0xff; -+ cyl16 = (sector >> 8) & 0xffff; -+ -+ devhead = (sector >> 24) & 0xf; -+ devhead |= ATA_LBA; -+ } else { -+ unsigned long blkno = (unsigned long) sector; -+ int sectorspertrack = priv->drive_chs_sectorspertrack; -+ int cylinders = priv->drive_chs_cylinders; -+ int heads = priv->drive_chs_heads; -+ -+ secnum = (blkno % sectorspertrack) + 1; -+ blkno -= secnum - 1; -+ -+ blkno /= sectorspertrack; -+ -+ devhead = blkno / cylinders; -+ -+ cyl16 = blkno % cylinders; -+ -+ if (devhead > (heads-1) ) { -+ return -1; -+ } -+ } -+ -+ seccnt = (u8) sector_num; -+ cyl_hi = (cyl16 >> 8) & 0xff; -+ cyl_lo = cyl16 & 0xff; -+ -+ write_devhead(priv, devhead); -+ write_sectornum(priv, secnum); -+ write_cyllo(priv, cyl_lo); -+ write_cylhi(priv, cyl_hi); -+ write_sectorcnt(priv, seccnt); -+ -+ NPRINTK("lba=%d, sector=%lld, seccnt=%x sector=0x%x (%d), cyl_lo=%x, cyl_hi=%x, cyl16=0x%x, devhead=%x\n", -+ priv->drive_canlba, sector, seccnt, secnum, secnum, cyl_lo, cyl_hi, cyl16, devhead); -+ -+ return 0; -+} -+ -+ -+ -+int mpc52xx_ata_doreset(struct mpc52xx_blockata_priv *priv) -+{ -+ int ret = 0; -+ -+ ret = wait_not_busy(priv); -+ if (ret!=0) -+ return -1; -+ -+ NPRINTK("%s: set reset %x\n", __func__, read_altstatus(priv) ); -+ -+ write_ctl(priv, ATA_SRST | ATA_NIEN); -+ ata_sleep(priv); -+ -+ NPRINTK("%s: release reset, %x\n", __func__, read_altstatus(priv)); -+ -+ write_ctl(priv, ATA_NIEN); -+ -+ -+ ata_sleep(priv); -+ -+ ret = wait_not_busy(priv); -+ if (ret<0) -+ return ret; -+ -+ write_devhead(priv, 0x00); -+ ata_sleep(priv); -+ -+ return wait_not_busy(priv); -+} -+ -+/* -+ * Export stuff -+*/ -+ -+EXPORT_SYMBOL(mpc52xx_ata_setupsector); -+EXPORT_SYMBOL(mpc52xx_ata_doreset); -+EXPORT_SYMBOL(mpc52xx_ata_regcheck); -diff --git a/drivers/block/mpc52xx/dodrivecmd.c b/drivers/block/mpc52xx/dodrivecmd.c -new file mode 100644 -index 0000000..afbfded ---- /dev/null -+++ b/drivers/block/mpc52xx/dodrivecmd.c -@@ -0,0 +1,138 @@ -+/* -+ * mpc52xx_atablock / dodrivecmd.c -+ * -+ * Copyright 2006 bplan GmbH -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file "COPYING" in the main directory of this archive -+ * for more details. -+ */ -+ -+/* -+ * handle the ioctl HDIO_DRIVE_CMD command -+*/ -+ -+/**************/ -+/**************/ -+/**************/ -+#include "mpc52xx_blockata.h" -+ -+/**************/ -+/**************/ -+/**************/ -+irqreturn_t ata_drivecmd_handler(struct mpc52xx_blockata_priv *priv, u8 ata_status) -+{ -+ NPRINTK("%s: status=0x%2.2x\n", __func__, ata_status); -+ -+ priv->ata_handler = ata_void_handler; -+ priv->io_inprogress = 0; -+ wake_up_interruptible(&priv->my_waitqueue); -+ -+ return IRQ_HANDLED; -+} -+ -+ int mpc52xx_ata_dodrivecmd( -+ struct mpc52xx_blockata_priv *priv, -+ unsigned long *irqflags, -+ u8 *args) -+ { -+ int ret; -+ u8 status; -+ u8 cmd; -+ -+ NPRINTK("arg [0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x],\n", args[0], args[1], args[2], args[3]); -+ -+ cmd = args[0]; -+ if ( (cmd==ATA_CMD_ID_ATAPI) || (cmd==ATA_CMD_ID_ATA) ) -+ { -+ int i; -+ u16 *iddest_u16; -+ u16 *drive_idendify; -+ -+ drive_idendify = priv->drive_identify; -+ iddest_u16 = (u16*) (&args[4]); -+ ret = 0; -+ -+ if (!priv->drive_identify_valid) { -+ if (priv->io_inprogress) { -+ VPRINTK("IO already in-progress, can not do more!\n"); -+ ret = -EBUSY; -+ goto end; -+ } -+ -+ priv->io_inprogress = 1; -+ ret = mpc52xx_ata_doidentify(priv); -+ priv->io_inprogress = 0; -+ -+ if (ret!=0) -+ goto end; -+ } -+ -+ for(i=0; i < 256; i++) -+ iddest_u16[i] = cpu_to_le16(drive_idendify[i]); -+ -+ goto end; -+ } -+ -+ if (priv->io_inprogress) -+ { -+ VPRINTK("IO already in-progress, can not do more!\n"); -+ ret = -EBUSY; -+ goto end; -+ } -+ -+ priv->io_inprogress = 1; -+ -+ // a drive cmd looks very simple -+ // simply copy the stuff in the drive reg and wait for some interrupt -+ -+ // Get preprepatre to receive an interrupt -+ priv->ata_handler = ata_drivecmd_handler; -+ -+ write_devfeature(priv, args[2]); -+ write_sectorcnt(priv, args[3]); -+ write_sectornum(priv, args[1]); -+ -+ write_cmd(priv, cmd); -+ -+ /* -+ * I'm 100% (well not even 10%) happy and confortable with this IRQ/wait stuff -+ * People should really write an how to "How to wait for an event in atomic section?" -+ */ -+ spin_unlock_irqrestore(&priv->lock, *irqflags); -+ ret = wait_event_interruptible_timeout(priv->my_waitqueue, priv->io_inprogress==0, 5*HZ); -+ spin_lock_irqsave(&priv->lock, *irqflags); -+ -+ if (ret<0) -+ { -+ ret = -ERESTARTSYS; -+ goto end; -+ } -+ -+ // Whatever happen, we can read back the status to users mess -+ //args[0] = read_devfeature(priv); -+ -+ status = read_status(priv); -+ if ( ATASTS_GOT_ERR(status) ) -+ ret = -EIO; -+ -+ // Not sure for arg0 -+ args[0] = status; -+ args[1] = read_devfeature(priv); -+ args[2] = read_sectorcnt(priv); -+ args[3] = read_sectornum(priv); -+ -+ NPRINTK("arg cmd=0x%2.2x, [0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x]\n", cmd, args[0], args[1], args[2], args[3]); -+ NPRINTK("return %d\n", ret); -+ -+ if(ret>0) -+ ret = 0; -+ -+ end: -+ priv->io_inprogress = 0; -+ priv->ata_handler = ata_void_handler; -+ return ret; -+ } -+ -+ -+EXPORT_SYMBOL(mpc52xx_ata_dodrivecmd); -diff --git a/drivers/block/mpc52xx/hwmisc.c b/drivers/block/mpc52xx/hwmisc.c -new file mode 100644 -index 0000000..862729a ---- /dev/null -+++ b/drivers/block/mpc52xx/hwmisc.c -@@ -0,0 +1,577 @@ -+/* -+ * mpc52xx_atablock / hwmisc.c -+ * -+ * Copyright 2006 bplan GmbH -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file "COPYING" in the main directory of this archive -+ * for more details. -+ */ -+ -+/* -+ * misc hw func (pio mode ...) -+*/ -+ -+/**************/ -+/**************/ -+/**************/ -+#include "mpc52xx_blockata.h" -+ -+/**************/ -+/**************/ -+/**************/ -+static int ata_doidentify_atapi(struct mpc52xx_blockata_priv *priv) -+{ -+ u16 * drive_idendify; -+ int ret; -+ u16 OneShort; -+ -+ NPRINTK("\n"); -+ -+ ret = 0; -+ drive_idendify = priv->drive_identify; -+ -+ NPRINTK("id[00]=0x%2.2x\n", drive_idendify[0]); -+ NPRINTK("id[85]=0x%2.2x\n", drive_idendify[85]); -+ -+ OneShort = drive_idendify[0]; -+ if ( (OneShort & 0xc000) != 0x8000) -+ return -1; -+ -+ if (OneShort & (1<<7) ) -+ priv->IsRemovable = 1; -+ else -+ priv->IsRemovable = 0; -+ -+ priv->drive_canlba = 0; -+ priv->IsATAPI = 1; -+ -+ priv->drive_identify_valid = 1; -+ -+ return ret; -+} -+ -+static int ata_doidentify(struct mpc52xx_blockata_priv *priv) -+{ -+ int ret; -+ -+ priv->drive_identify_valid = 0; -+ -+ ret = wait_ready(priv); -+ if (ret!=0) -+ goto error; -+ -+ write_cmd(priv, priv->UsePacket ? ATA_CMD_ID_ATAPI : ATA_CMD_ID_ATA); -+ ret = wait_drq(priv); -+ if (ret!=0) -+ goto error; -+ -+ ret = mpc52xx_ata_docpupollread(priv, priv->drive_identify, 256); -+ if (ret<0) -+ goto error; -+ -+ priv->drive_identify[49] = priv->drive_identify[49] & ~(1<<8); -+ -+ memcpy(priv->drive_model, (char *) & priv->drive_identify[27], 40); -+ priv->drive_model[39] = '\0'; -+ memcpy(priv->drive_firmware, (char *) & priv->drive_identify[23], 8); -+ priv->drive_firmware[7] = '\0'; -+ -+ if (priv->UsePacket) -+ return ata_doidentify_atapi(priv); -+ -+ priv->drive_heads = priv->drive_identify[3]; -+ priv->drive_cylinders = priv->drive_identify[1]; -+ priv->drive_sectorspertrack = priv->drive_identify[6]; -+ priv->drive_cap = priv->drive_identify[49]; -+ -+ priv->drive_canlba = priv->drive_cap & CAPF_LBA; -+ priv->drive_canlba48 = ((priv->drive_identify[83]) & (1 << 10)) == (1 << 10) ; -+ -+ if (priv->drive_canlba) { -+ priv->drive_sectors = (sector_t) -+ ( (priv->drive_identify[60] & 0xffff) -+ | ( (priv->drive_identify[61] << 16) & 0xffff0000) ); -+ } else { -+ priv->drive_sectors = (sector_t) -+ ( (priv->drive_identify[57] & 0xffff) -+ | ( (priv->drive_identify[58] << 16) & 0xffff0000) ); -+ } -+ -+ -+ NPRINTK("%s: id[0]=%x\n", __func__, priv->drive_identify[0]); -+ NPRINTK("%s: id[1]=%x\n", __func__, priv->drive_identify[1]); -+ NPRINTK("%s: id[3]=%x\n", __func__, priv->drive_identify[3]); -+ NPRINTK("%s: id[6]=%x\n", __func__, priv->drive_identify[6]); -+ NPRINTK("%s: id[53]=%x\n", __func__, priv->drive_identify[53]); -+ NPRINTK("%s: id[54]=%x\n", __func__, priv->drive_identify[54]); -+ NPRINTK("%s: id[55]=%x\n", __func__, priv->drive_identify[55]); -+ NPRINTK("%s: id[56]=%x\n", __func__, priv->drive_identify[56]); -+ -+ NPRINTK("%s: id[57/58]=%x %x\n", __func__, priv->drive_identify[57], priv->drive_identify[58]); -+ NPRINTK("%s: id[60/61]=%x %x\n", __func__, priv->drive_identify[57], priv->drive_identify[58]); -+ NPRINTK("%s: id[82]=%x\n", __func__, priv->drive_identify[82]); -+ NPRINTK("%s: id[83]=%x\n", __func__, priv->drive_identify[83]); -+ -+ -+ NPRINTK("%s: model=%s, fw=%s. %d heads, %d cylinders, %lld sectors. LBA=%d\n", -+ __func__, -+ priv->drive_model, priv->drive_firmware, -+ priv->drive_heads, priv->drive_cylinders, priv->drive_sectors, priv->drive_canlba ); -+ -+ priv->drive_identify_valid = 1; -+ return 0; -+ -+error: -+ return -1; -+} -+ -+int mpc52xx_ata_doidentify(struct mpc52xx_blockata_priv *priv) -+{ -+ return ata_doidentify(priv); -+} -+ -+/**************/ -+/**************/ -+int mpc52xx_ata_setpiomode(struct mpc52xx_blockata_priv *priv, int pio_mode) -+{ -+ u8 setfeature_val; -+ int ret; -+ -+ NPRINTK("%s: pio_mode=%d\n", __func__, pio_mode); -+ -+ switch(pio_mode) { -+ case 0: -+ setfeature_val = XFER_PIO_0; -+ break; -+ case 1: -+ setfeature_val = XFER_PIO_1; -+ break; -+ case 2: -+ setfeature_val = XFER_PIO_2; -+ break; -+ case 3: -+ setfeature_val = XFER_PIO_3; -+ break; -+ case 4: -+ setfeature_val = XFER_PIO_4; -+ break; -+ default: -+ return -1; -+ } -+ -+ write_sectorcnt(priv, setfeature_val); -+ write_devfeature(priv, SETFEATURES_XFER); -+ -+ ret = wait_ready(priv); -+ if (ret !=0) -+ return ret; -+ -+ write_cmd(priv, ATA_CMD_SET_FEATURES); -+ -+ return wait_not_busy(priv); -+} -+ -+/* -+ * if pio_arg is <0 then, return the best pio mode available -+*/ -+int mpc52xx_ata_isthispiovalid(struct mpc52xx_blockata_priv *priv, int pio_arg) -+{ -+ int ret; -+ int mode; -+ -+ u16 id_fieldval; -+ u16 id_advpio; -+ -+ NPRINTK("pio_arg=%d\n", pio_arg); -+ -+ if (!priv->drive_identify_valid) { -+ ret = ata_doidentify(priv); -+ if (ret!=0) -+ return -1; -+ } -+ -+ id_advpio = priv->drive_identify[64]; -+ id_fieldval = priv->drive_identify[53]; -+ -+ NPRINTK("id_advpio=%x, id_fieldval=%x\n",id_advpio, id_fieldval); -+ -+ if (pio_arg<0) { -+ pio_arg = 2; -+ -+ if (id_fieldval & 0x0002) { -+ if (id_advpio&0x2) -+ pio_arg = 4; -+ else if (id_advpio&0x1) -+ pio_arg = 3; -+ } -+ } -+ -+ NPRINTK("pio_arg=%d\n", pio_arg); -+ -+ switch(pio_arg) { -+ case 0: -+ case 1: -+ case 2: -+ mode = pio_arg; -+ break; -+ -+ case 3: -+ mode = ( (id_fieldval&0x0002) && (id_advpio&0x1) )? pio_arg : -1; -+ break; -+ -+ case 4: -+ mode = ( (id_fieldval&0x0002) && (id_advpio&0x2) )? pio_arg : -1; -+ break; -+ -+ default: -+ mode = -1; -+ } -+ -+ return mode; -+} -+ -+ -+/**************/ -+#define IDENTIFY_MULTI_MAXSECMASK 0x00ff -+#define IDENTIFY_MULTI_OKFLAG 0x00100 -+ -+int mpx52xx_ata_dosetmulti(struct mpc52xx_blockata_priv *priv, u16 val) -+{ -+ int ret; -+ -+ NPRINTK("set multi to %d\n", val); -+ -+ if (priv->UsePacket) -+ return -1; -+ -+ write_sectorcnt(priv, val&0xff); -+ -+ ret = wait_ready(priv); -+ if (ret !=0) -+ return -1; -+ -+ ATA_DUMPREG -+ write_cmd(priv, ATA_CMD_SETMULTI); -+ -+ ata_sleep(priv); -+ ret = wait_not_busy(priv); -+ if (ret !=0) -+ return -1; -+ -+ return 0; -+} -+ -+#define IS_MULTIOK(__identify_multi__) \ -+( \ -+ (__identify_multi__ & IDENTIFY_MULTI_OKFLAG) \ -+ && (__identify_multi__ & IDENTIFY_MULTI_MAXSECMASK) \ -+) -+ -+static int ata_multi_probeandset(struct mpc52xx_blockata_priv *priv) -+{ -+ int ret; -+ u16 identify_multi; -+ u16 identify_multimax; -+ -+ priv->multi_available = 0; -+ -+ if (priv->UsePacket) -+ return -1; -+ -+ NPRINTK("id[59]=0x%x, id[47]=0x%x\n", priv->drive_identify[59], priv->drive_identify[47]); -+ -+ identify_multi = priv->drive_identify[59]; -+ if ( IS_MULTIOK(identify_multi) ) { -+ priv->multi_available = 1; -+ priv->multi_secpercmd = identify_multi & IDENTIFY_MULTI_MAXSECMASK; -+ } else { -+ identify_multimax = priv->drive_identify[47] & IDENTIFY_MULTI_MAXSECMASK; -+ ret = mpx52xx_ata_dosetmulti(priv, identify_multimax); -+ if (ret<0) -+ goto error; -+ -+ ret = ata_doidentify(priv); -+ if (ret!=0) -+ goto error; -+ -+ NPRINTK("idenditify updated, identify_multimax=%d, s=%x, id[59]=0x%x, id[47]=0x%x\n", -+ identify_multimax, read_altstatus(priv), priv->drive_identify[59], priv->drive_identify[47]); -+ -+ identify_multi = priv->drive_identify[59]; -+ -+ if ( IS_MULTIOK(identify_multi) ) { -+ priv->multi_available = 1; -+ priv->multi_secpercmd = identify_multi & IDENTIFY_MULTI_MAXSECMASK; -+ } else { -+ priv->multi_secpercmd = MAX_SECPERREQ; -+ } -+ -+ } -+ -+ return 0; -+ -+error: -+ priv->multi_secpercmd = MAX_SECPERREQ; -+ priv->multi_available = 0; -+ -+ return ret; -+} -+ -+ -+/**************/ -+static int ata_dodiag(struct mpc52xx_blockata_priv *priv) -+{ -+ int ret; -+ u8 diagcode; -+ u8 sectorcount; -+ u8 lbah; -+ u8 lbal; -+ u8 lbam; -+ -+ NPRINTK("1\n"); -+ -+ ret = wait_not_busy(priv); -+ if (ret!=0) -+ goto error; -+ -+ NPRINTK("cmd\n"); -+ write_cmd(priv, ATA_CMD_EDD); -+ -+ wait_not_busy(priv); -+ diagcode = read_devfeature(priv); -+ -+ NPRINTK("diagcode=%x\n", diagcode); -+ -+ /* Check if this device implement the PACKET feature set -+ * see ATAPI6 spec section 9.12 -+ * Non Packet has this signature: -+ * Sector Count 01h -+ * LBA Low 01h -+ * LBA Mid 00h -+ * LBA High 00h -+ * Device 00h -+ * -+ * Packet has this signature: -+ * Sector Count 01h -+ * LBA Low 01h -+ * LBA Mid 14h -+ * LBA High EBh -+ * -+ * -+ */ -+ sectorcount = read_sectorcnt(priv); -+ lbal = read_sectornum(priv); -+ lbam = read_cyllo(priv); -+ lbah = read_cylhi(priv); -+ -+ NPRINTK("sc=%2.2x lbal=%2.2x lbam=%2.2x lbah=%2.2x\n", sectorcount, lbal, lbam, lbah); -+ -+ if ( (sectorcount != 0x01) && (lbal != 0x01) ) -+ goto error; -+ -+ if ( (lbam==0) && (lbah==0) ) -+ priv->UsePacket = 0; -+ else if ((lbam==0x14) && (lbah==0xeb) ) -+ priv->UsePacket = 1; -+ else -+ goto error; -+ -+ return ! (diagcode & 0x01); -+ -+error: -+ NPRINTK("error %d\n", ret); -+ ATA_DUMPREG -+ -+ return -1; -+} -+/**************/ -+void mpc52xx_ata_dumpreg(struct mpc52xx_blockata_priv *priv) -+{ -+ u8 seccnt, sector, cyl_lo, cyl_hi, error, status; -+ -+ seccnt = read_sectorcnt(priv); -+ sector = read_sectornum(priv); -+ cyl_lo = read_cyllo(priv); -+ cyl_hi = read_cylhi(priv); -+ error = read_error(priv); -+ status = read_altstatus(priv); -+ -+ VPRINTK("seccnt=%x sector=%x, cyl_lo=%x, cyl_hi=%x, error=%x, status =%x \n", -+ seccnt, sector, cyl_lo, cyl_hi, error, status); -+} -+ -+static int ata_doreset(struct mpc52xx_blockata_priv *priv) -+{ -+ int ret = 0; -+ -+ ret = wait_not_busy(priv); -+ if (ret!=0) -+ return -1; -+ -+ NPRINTK("set reset %x\n", read_altstatus(priv) ); -+ write_ctl(priv, ATA_SRST | ATA_NIEN); -+ ata_sleep(priv); -+ -+ NPRINTK("release reset, %x\n", read_altstatus(priv)); -+ write_ctl(priv, ATA_NIEN); -+ -+ ata_sleep(priv); -+ -+ ret = wait_not_busy(priv); -+ if (ret<0) -+ return ret; -+ -+ write_devhead(priv, 0x00); -+ ata_sleep(priv); -+ -+ wait_not_busy(priv); -+ if (ret<0) -+ return ret; -+ -+ return ATASTS_GOT_ERR( read_altstatus(priv) ); -+} -+ -+/**************/ -+static int ata_setupchs(struct mpc52xx_blockata_priv *priv) -+{ -+ int ret = 0; -+ -+ NPRINTK("s=0x%2.2x, lba=%d, secper=%d, heads=%dn", -+ read_altstatus(priv), -+ priv->drive_canlba, -+ priv->drive_sectorspertrack, -+ priv->drive_heads); -+ -+ priv->drive_chs_ok = 0; -+ -+ if -+ ( -+ (priv->drive_sectorspertrack == 0) -+ || priv->drive_canlba -+ ) -+ return -1; -+ -+ if (!priv->drive_identify_valid) { -+ ret = ata_doidentify(priv); -+ if (ret!=0) -+ return -1; -+ } -+ -+ NPRINTK("wait1 s=%2.2x\n", read_altstatus(priv) ); -+ ret = wait_not_busy(priv); -+ if (ret<0) -+ return ret; -+ -+ write_sectorcnt(priv, priv->drive_sectorspertrack ); -+ write_devhead(priv, priv->drive_heads - 1); -+ -+ NPRINTK("wait2 s=%2.2x\n", read_altstatus(priv) ); -+ ret = wait_ready(priv); -+ if (ret<0) { -+ ATA_DUMPREG -+ return ret; -+ } -+ -+ write_cmd(priv, ATA_CMD_INIT_DEV_PARAMS); -+ -+ NPRINTK("wait3 s=%2.2x\n", read_altstatus(priv) ); -+ ret = wait_not_busy(priv); -+ if (ret<0) { -+ ATA_DUMPREG -+ return ret; -+ } -+ -+ ret = ata_doidentify(priv); -+ if (ret!=0) -+ return ret; -+ -+ if (!(priv->drive_identify[53] & 0x0001)) -+ return -1; -+ -+ priv->drive_chs_ok = 1; -+ -+ priv->drive_chs_heads = priv->drive_identify[54]; -+ priv->drive_chs_cylinders = priv->drive_identify[55]; -+ priv->drive_chs_sectorspertrack = priv->drive_identify[56]; -+ -+ NPRINTK("ok. CHS=%d/%d/%ds=0x%2.2x\n", -+ read_altstatus(priv), -+ priv->drive_chs_cylinders, -+ priv->drive_chs_heads, -+ priv->drive_chs_sectorspertrack); -+ -+ return 0; -+} -+ -+/**************/ -+/**************/ -+/**************/ -+ -+/* -+ * Simple and dump drive init func -+ * reset, sanity check, drive presence, get drive info -+*/ -+int mpc52xx_ata_init_drive(struct mpc52xx_blockata_priv *priv) -+{ -+ int ret; -+ -+ ret = wait_not_busy(priv); -+ if (ret!=0) -+ goto error; -+ -+ write_ctl(priv, ATA_NIEN); -+ -+ NPRINTK("select dev 0\n"); -+ write_devhead(priv, 0x00); -+ -+ ata_sleep(priv); -+ -+ ata_doreset(priv); -+ -+ /* Some check ... */ -+ NPRINTK("regcheck %x\n", read_altstatus(priv)); -+ ret = mpc52xx_ata_regcheck(priv); -+ if (ret!=0) -+ goto error; -+ -+ /* diagnostic */ -+ NPRINTK("diag %x\n", read_altstatus(priv)); -+ ret = ata_dodiag(priv); -+ if (ret!=0) -+ goto error; -+ -+ /* Get information from the drive */ -+ NPRINTK("do id %x, UsePacket=%d\n", read_altstatus(priv), priv->UsePacket); -+ if (!priv->drive_identify_valid) { -+ ret = ata_doidentify(priv); -+ if (ret!=0) -+ goto error; -+ } -+ -+ ata_setupchs(priv); -+ ata_multi_probeandset(priv); -+ -+ return ret; -+ -+error: -+ NPRINTK("%s: error %d, altsts=%x, err=%x\n", __func__, ret, read_altstatus(priv), read_error(priv)); -+ ATA_DUMPREG; -+ -+ return -1; -+} -+ -+u32 mpc52xx_ata_getregisterbase(struct mpc52xx_blockata_priv *priv) -+{ return 0xf0003a00; } -+ -+/* -+ * Export stuff -+*/ -+ -+EXPORT_SYMBOL(mpc52xx_ata_init_drive); -+EXPORT_SYMBOL(mpc52xx_ata_getregisterbase); -+EXPORT_SYMBOL(mpc52xx_ata_doidentify); -+EXPORT_SYMBOL(mpc52xx_ata_setpiomode); -+ -+EXPORT_SYMBOL(mpc52xx_ata_isthispiovalid); -+EXPORT_SYMBOL(mpx52xx_ata_dosetmulti); -diff --git a/drivers/block/mpc52xx/mpc52xx_blockata.h b/drivers/block/mpc52xx/mpc52xx_blockata.h -new file mode 100644 -index 0000000..69a6a88 ---- /dev/null -+++ b/drivers/block/mpc52xx/mpc52xx_blockata.h -@@ -0,0 +1,311 @@ -+/* -+ * mpc52xx_blockata.h -+ * -+ * Copyright 2006 bplan GmbH -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file "COPYING" in the main directory of this archive -+ * for more details. -+ */ -+ -+ -+#ifndef __MPC52xx_BLOCKATA_H__ -+#define __MPC52xx_BLOCKATA_H__ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+/**************/ -+/**************/ -+/**************/ -+//#define __DEBUG__ -+ -+/**************/ -+/**************/ -+/**************/ -+#include -+ -+#include "protos.h" -+#include "mpc52xx_ide.h" -+ -+ -+/**************/ -+/**************/ -+/**************/ -+ -+#ifdef __DEBUG__ -+#define DEBUG -+#define NPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args) -+//#define NPRINTK2(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args) -+#define NPRINTK2(fmt, args...) -+ -+#define ATA_DUMPREG mpc52xx_ata_dumpreg(priv); -+ -+#else -+#define NPRINTK(fmt, args...) -+#define NPRINTK2(fmt, args...) -+#define ATA_DUMPREG -+#endif -+ -+/**************/ -+/**************/ -+/**************/ -+ -+#ifdef CONFIG_BLK_DEV_MPC52XX_ATAPIO_VERBOSE -+#define VPRINTK(fmt, args...) if ( printk_ratelimit() ) { printk(KERN_ERR DEVSKEL_DEVICENAME ": " fmt, ## args); } -+#else -+#define VPRINTK(fmt, args...) -+#endif -+ -+#define DEVICE_USERLIMIT 1024 -+#define KERNEL_SECTOR_SIZE 512 -+ -+// I notice 8 gives some good result -+#define DRIVER_MAXHWSEG 8 -+ -+/**************/ -+/**************/ -+/**************/ -+ -+ -+#ifndef ATA_CMD_RESET -+#define ATA_CMD_RESET 0x08 -+#endif -+ -+#ifndef ATA_CMD_SETMULTI -+#define ATA_CMD_SETMULTI 0xc6 -+#endif -+ -+/**************/ -+/**************/ -+/**************/ -+ -+#ifndef bio_cur_sectors_idx -+#define bio_cur_sectors_idx(__bio__,__idx__) (bio_iovec_idx((__bio__), (__idx__))->bv_len >> 9) -+#endif -+ -+#ifndef bio_getnext -+#define bio_getnext(__bio__) ( (__bio__)->bi_next ) -+#endif -+ -+ -+#ifndef bio_getsector -+#define bio_getsector(__bio__) ( (__bio__)->bi_sector ) -+#endif -+ -+#ifndef bio_getcuridx -+#define bio_getcuridx(__bio__) ( (__bio__)->bi_idx ) -+#endif -+ -+#ifndef bio_islastidx -+#define bio_islastidx(__bio__, __idx__) ( (__idx__) >= (__bio__)->bi_vcnt ) -+#endif -+ -+ -+ -+/**************/ -+/**************/ -+/**************/ -+ -+/* -+ * -+ * TO DO: -+ * - better error handling -+ * - Transaction timeout/reset -+ * - test and fix LBA48 addressing -+ * - code, test and fix CHS addressing -+ * -+ * History -+ * - 0.1. 27.06.2006 -+ * Initial revision -+ * PIO func, SDMA/CPU polling... -+ * Reliable operation (1 or 2 MB/s) -+ * -+ * - 0.2. 28.06.2006 -+ * Interrupt based driver! -+ * IRQ handlers, handles better bio, bio vec, req... -+ * Reliable operation (write 1.5MB/s, read 3.5MB/s to 6.5MB/s) -+ * -+ * - 0.3b1. 29.06.2006 -+ * Cleanup and small fixes -+ * Wait for DRQ interrupt instead of polling for read -+ * Add user count feature -+ * -+ * - 0.3b2. 30.06.2006 -+ * Fixed the nopen/nrelease -> release was disabling IRQ even if -+ * there was still some people using it. I don't even speak about open! -+ * Cleanup and small fixes -+ * -+ * - 0.4 02.07.2006 -+ * Driver totaly cleaned up and spread other severals sources file -+ * Implemented LBA48 but untested due to lack of drive (you've been warmed!) -+ * -+ * - 0.5 07.07.2006 -+ * General cleanup -+ * Better SDMA task configuration -+ * Try to adjust the block queue config -+ * -+ * - 0.6b1 30.07.2006 -+ * General cleanup -+ * Add HIDIO_DRIVE_CMD support -+ * Fixed (a bit) spinlock_* -+ * Primilary ATAPI/Packet support -+ * -+ * - 0.6 31.07.2006 -+ * General cleanup -+ * Nicely failed when ATAPI/Packet command is needed -+ * Fixed HDIO_DRIVE_CMD/Identify -+ * -+ * - 0.7 18.10.2006 -+ * General cleanup -+ * fix text layout for Linux patch -+ * First try to init the drive and then the Linux block system becase -+ * the block code BUG() on free -+*/ -+ -+ -+/**************/ -+/**************/ -+/**************/ -+ -+#define MAX_DMA_BUFFERS 4 -+#define MAX_DMA_BUFFER_SIZE 512*256 -+ -+#define DEVSKEL_DRIVERVERSION "0.7" -+#define DEVSKEL_DRIVERNAME "MPC52xx ATA/PIO" -+#define DEVSKEL_DEVICENAME "mpc52xx_ata" -+ -+#define MAX_SECPERREQ DRIVER_MAXHWSEG -+ -+ -+/**************/ -+/**************/ -+/**************/ -+ -+#ifndef MPC52xx_ATA_OFFSET -+#define MPC52xx_ATA_OFFSET (0x3a00) -+#endif -+ -+#define ATAFIFO_BUSADDR ( (u32) 0xf0003a60 ) -+ -+ -+/**************/ -+/**************/ -+/**************/ -+ -+/* Helper to compute timing parameters */ -+#define CALC_CLK_VALUE_UP(c,v) (((v) + c - 1) / c) -+ -+/**************/ -+/**************/ -+/**************/ -+/* Private structures used by the driver */ -+struct mpc52xx_ata_timings -+{ -+ u32 pio1; -+ u32 pio2; -+ u32 mdma1; -+ u32 mdma2; -+ u32 udma1; -+ u32 udma2; -+ u32 udma3; -+ u32 udma4; -+ u32 udma5; -+ int using_udma; -+}; -+ -+/**************/ -+/**************/ -+/**************/ -+struct mpc52xx_blockata_priv -+{ -+ struct gendisk *device_gendisk; -+ struct request_queue *device_queue; -+ int major; -+ -+ spinlock_t lock; -+ -+ wait_queue_head_t my_waitqueue; -+ -+ int drive_inited; -+ int usercnt; -+ -+ int drive_identify_valid; -+ u16 drive_identify[256]; -+ -+ char drive_model[40]; -+ char drive_firmware[8]; -+ -+ sector_t drive_sectors; -+ int drive_sectorspertrack; -+ int drive_cylinders; -+ int drive_heads; -+ -+ int drive_chs_ok; -+ int drive_chs_sectorspertrack; -+ int drive_chs_cylinders; -+ int drive_chs_heads; -+ -+#define CAPF_LBA (1<<9) -+ u16 drive_cap; -+ int drive_canlba; -+ int drive_canlba48; -+ -+ u8 curio_atacmd; -+ -+ int io_inprogress; -+ -+ unsigned int ipb_period; /* in ps */ -+ -+ struct mpc52xx_ata __iomem *ata_regs; -+ u32 ata_regs_bus; -+ struct mpc52xx_ata_timings timings[2]; -+ -+ struct bestcomm_taskhandle taskhandle; -+ struct bestcomm_taskhandle *sdma; -+ -+ int ata_irq; -+ int sdma_irq; -+ -+ int multi_secpercmd; -+ int multi_available; -+ -+ irqreturn_t (*sdma_handler) (struct mpc52xx_blockata_priv *priv); -+ irqreturn_t (*ata_handler) (struct mpc52xx_blockata_priv *priv, u8 ata_status); -+ -+ int curio_sectodo; -+ -+ int curio_secidx; -+ int curio_secpershot; -+ u16 *curio_buffer; -+ -+ struct request *curio_req; -+ struct bio *curio_bio; -+ int curio_bioidx; -+ sector_t curio_sector; -+ -+ int piomode; -+ -+ int UsePacket; -+ int IsATAPI; -+ int IsRemovable; -+}; -+ -+ -+/**************/ -+/**************/ -+/**************/ -+ -+#include "piofunc_inline.h" -+ -+#endif -diff --git a/drivers/block/mpc52xx/mpc52xx_ide.h b/drivers/block/mpc52xx/mpc52xx_ide.h -new file mode 100644 -index 0000000..6cd35eb ---- /dev/null -+++ b/drivers/block/mpc52xx/mpc52xx_ide.h -@@ -0,0 +1,131 @@ -+/* -+ * drivers/ide/ppc/mpc52xx_ide.h -+ * -+ * Definitions for the Freescale MPC52xx on-chip IDE interface -+ * -+ * -+ * Copyright (C) 2006 Sylvain Munaut -+ * Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt -+ * -+ * 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. -+ */ -+ -+#ifndef __MPC52xx_IDE_H__ -+#define __MPC52xx_IDE_H__ -+ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+/* Bit definitions inside the registers */ -+ -+#define MPC52xx_ATA_HOSTCONF_SMR 0x80000000UL /* State machine reset */ -+#define MPC52xx_ATA_HOSTCONF_FR 0x40000000UL /* FIFO Reset */ -+#define MPC52xx_ATA_HOSTCONF_IE 0x02000000UL /* Enable interrupt in PIO */ -+#define MPC52xx_ATA_HOSTCONF_IORDY 0x01000000UL /* Drive supports IORDY protocol */ -+ -+#define MPC52xx_ATA_HOSTSTAT_TIP 0x80000000UL /* Transaction in progress */ -+#define MPC52xx_ATA_HOSTSTAT_UREP 0x40000000UL /* UDMA Read Extended Pause */ -+#define MPC52xx_ATA_HOSTSTAT_RERR 0x02000000UL /* Read Error */ -+#define MPC52xx_ATA_HOSTSTAT_WERR 0x01000000UL /* Write Error */ -+ -+#define MPC52xx_ATA_FIFOSTAT_EMPTY 0x01 /* FIFO Empty */ -+ -+#define MPC52xx_ATA_DMAMODE_WRITE 0x01 /* Write DMA */ -+#define MPC52xx_ATA_DMAMODE_READ 0x02 /* Read DMA */ -+#define MPC52xx_ATA_DMAMODE_UDMA 0x04 /* UDMA enabled */ -+#define MPC52xx_ATA_DMAMODE_IE 0x08 /* Enable drive interrupt to CPU in DMA mode */ -+#define MPC52xx_ATA_DMAMODE_FE 0x10 /* FIFO Flush enable in Rx mode */ -+#define MPC52xx_ATA_DMAMODE_FR 0x20 /* FIFO Reset */ -+#define MPC52xx_ATA_DMAMODE_HUT 0x40 /* Host UDMA burst terminate */ -+ -+ -+/* Structure of the hardware registers */ -+struct mpc52xx_ata -+{ -+ -+ /* Host interface registers */ -+ u32 config; /* ATA + 0x00 Host configuration */ -+ u32 host_status; /* ATA + 0x04 Host controller status */ -+ u32 pio1; /* ATA + 0x08 PIO Timing 1 */ -+ u32 pio2; /* ATA + 0x0c PIO Timing 2 */ -+ u32 mdma1; /* ATA + 0x10 MDMA Timing 1 */ -+ u32 mdma2; /* ATA + 0x14 MDMA Timing 2 */ -+ u32 udma1; /* ATA + 0x18 UDMA Timing 1 */ -+ u32 udma2; /* ATA + 0x1c UDMA Timing 2 */ -+ u32 udma3; /* ATA + 0x20 UDMA Timing 3 */ -+ u32 udma4; /* ATA + 0x24 UDMA Timing 4 */ -+ u32 udma5; /* ATA + 0x28 UDMA Timing 5 */ -+ u32 share_cnt; /* ATA + 0x2c ATA share counter */ -+ u32 reserved0[3]; -+ -+ /* FIFO registers */ -+ u32 fifo_data; /* ATA + 0x3c */ -+ u8 fifo_status_frame; /* ATA + 0x40 */ -+ u8 fifo_status; /* ATA + 0x41 */ -+ u16 reserved7[1]; -+ u8 fifo_control; /* ATA + 0x44 */ -+ u8 reserved8[5]; -+ u16 fifo_alarm; /* ATA + 0x4a */ -+ u16 reserved9; -+ u16 fifo_rdp; /* ATA + 0x4e */ -+ u16 reserved10; -+ u16 fifo_wrp; /* ATA + 0x52 */ -+ u16 reserved11; -+ u16 fifo_lfrdp; /* ATA + 0x56 */ -+ u16 reserved12; -+ u16 fifo_lfwrp; /* ATA + 0x5a */ -+ -+ /* Drive TaskFile registers */ -+ u8 tf_control; /* ATA + 0x5c TASKFILE Control/Alt Status */ -+ u8 reserved13[3]; -+ u16 tf_data; /* ATA + 0x60 TASKFILE Data */ -+ u16 reserved14; -+ u8 tf_features; /* ATA + 0x64 TASKFILE Features/Error */ -+ u8 reserved15[3]; -+ u8 tf_sec_count; /* ATA + 0x68 TASKFILE Sector Count */ -+ u8 reserved16[3]; -+ u8 tf_sec_num; /* ATA + 0x6c TASKFILE Sector Number */ -+ u8 reserved17[3]; -+ u8 tf_cyl_low; /* ATA + 0x70 TASKFILE Cylinder Low */ -+ u8 reserved18[3]; -+ u8 tf_cyl_high; /* ATA + 0x74 TASKFILE Cylinder High */ -+ u8 reserved19[3]; -+ u8 tf_dev_head; /* ATA + 0x78 TASKFILE Device/Head */ -+ u8 reserved20[3]; -+ u8 tf_command; /* ATA + 0x7c TASKFILE Command/Status */ -+ u8 dma_mode; /* ATA + 0x7d ATA Host DMA Mode configuration */ -+ u8 reserved21[2]; -+}; -+ -+ -+/* Function definition */ -+ -+ -+static inline void -+mpc52xx_ide_wait_tip_bit_clear(struct mpc52xx_ata __iomem *regs) -+{ -+ int timeout = 1000; -+ -+ while (in_be32(®s->host_status) & MPC52xx_ATA_HOSTSTAT_TIP) -+ if (timeout-- == 0) -+ { -+ printk(KERN_ERR -+ "mpc52xx-ide: Timeout waiting for TIP clear\n"); -+ break; -+ } -+ udelay(10); /* FIXME: Necessary ??? */ -+} -+ -+extern void mpc52xx_ide_setup_hwif_iops(ide_hwif_t *hwif); -+ -+ -+#endif /* __MPC52xx_IDE_H__ */ -+ -diff --git a/drivers/block/mpc52xx/piofunc_inline.h b/drivers/block/mpc52xx/piofunc_inline.h -new file mode 100644 -index 0000000..ca89dec ---- /dev/null -+++ b/drivers/block/mpc52xx/piofunc_inline.h -@@ -0,0 +1,250 @@ -+/* -+ * mpc52xx_atablock / piofunc_inline.h -+ * -+ * Copyright 2006 bplan GmbH -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file "COPYING" in the main directory of this archive -+ * for more details. -+ */ -+ -+ -+#ifndef __MPC52xx_BLOCKATA_PIOFUNC_H__ -+#define __MPC52xx_BLOCKATA_PIOFUNC_H__ -+ -+ -+/**************/ -+/**************/ -+/**************/ -+ -+#include "mpc52xx_blockata.h" -+ -+/**************/ -+/**************/ -+/**************/ -+ -+#include -+ -+/* -+ * Pio helper -+*/ -+ -+static inline u8 read_altstatus(struct mpc52xx_blockata_priv *priv) -+{ -+ struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs; -+ return readb(&ata_regs->tf_control); -+} -+ -+static inline u8 read_status(struct mpc52xx_blockata_priv *priv) -+{ -+ struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs; -+ return readb(&ata_regs->tf_command); -+} -+ -+static inline u8 read_sectorcnt(struct mpc52xx_blockata_priv *priv) -+{ -+ struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs; -+ return readb(&ata_regs->tf_sec_count); -+} -+ -+static inline u8 read_sectornum(struct mpc52xx_blockata_priv *priv) -+{ -+ struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs; -+ return readb(&ata_regs->tf_sec_num); -+} -+ -+static inline u8 read_cylhi(struct mpc52xx_blockata_priv *priv) -+{ -+ struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs; -+ return readb(&ata_regs->tf_cyl_high); -+} -+ -+static inline u8 read_cyllo(struct mpc52xx_blockata_priv *priv) -+{ -+ struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs; -+ return readb(&ata_regs->tf_cyl_low); -+} -+ -+static inline u8 read_devfeature(struct mpc52xx_blockata_priv *priv) -+{ -+ struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs; -+ return readb(&ata_regs->tf_features); -+} -+static inline u8 read_error(struct mpc52xx_blockata_priv *priv) -+{ -+ return read_devfeature(priv); -+} -+ -+static inline u16 read_data(struct mpc52xx_blockata_priv *priv) -+{ -+ struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs; -+ return readw(&ata_regs->tf_data); -+} -+ -+/**************/ -+static inline void write_data(struct mpc52xx_blockata_priv *priv, u16 val) -+{ -+ struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs; -+ writew(val, &ata_regs->tf_data); -+} -+ -+static inline void write_devfeature(struct mpc52xx_blockata_priv *priv, u8 val) -+{ -+ struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs; -+ writeb(val, &ata_regs->tf_features); -+} -+ -+ -+static inline void write_cyllo(struct mpc52xx_blockata_priv *priv, u8 val) -+{ -+ struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs; -+ writeb(val, &ata_regs->tf_cyl_low); -+} -+ -+static inline void write_cylhi(struct mpc52xx_blockata_priv *priv, u8 val) -+{ -+ struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs; -+ writeb(val, &ata_regs->tf_cyl_high); -+} -+ -+static inline void write_cmd(struct mpc52xx_blockata_priv *priv, u8 val) -+{ -+ struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs; -+ writeb(val, &ata_regs->tf_command); -+} -+ -+static inline void write_ctl(struct mpc52xx_blockata_priv *priv, u8 val) -+{ -+ struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs; -+ writeb(val, &ata_regs->tf_control); -+} -+ -+static inline void write_sectornum(struct mpc52xx_blockata_priv *priv, u8 val) -+{ -+ struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs; -+ writeb(val, &ata_regs->tf_sec_num); -+} -+ -+static inline void write_sectorcnt(struct mpc52xx_blockata_priv *priv, u8 val) -+{ -+ struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs; -+ writeb(val, &ata_regs->tf_sec_count); -+} -+ -+ -+static inline void write_devhead(struct mpc52xx_blockata_priv *priv, u8 val) -+{ -+ struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs; -+ writeb(val, &ata_regs->tf_dev_head); -+} -+ -+ -+/**************/ -+static inline void ata_sleep(struct mpc52xx_blockata_priv *priv) -+{ -+ read_altstatus(priv); -+ udelay(500); -+} -+ -+static inline void ata_sleep2(struct mpc52xx_blockata_priv *priv) -+{ -+ read_altstatus(priv); -+ udelay(1); -+} -+ -+/**************/ -+#define ATASTS_IS_NOTBUSY(__status__) ( ! ( (__status__) & ATA_BUSY) ) -+#define ATASTS_IS_READY(__status__) ( ( (__status__) & (ATA_DRDY|ATA_BUSY) ) == ATA_DRDY ) -+#define ATASTS_IS_DRQ(__status__) ( (__status__) & ATA_DRQ) -+#define ATASTS_GOT_ERR(__status__) ( (__status__) & ATA_ERR) -+ -+#define WAIT_TIMEOUT (1000*1000) -+ -+ -+static inline u8 read_mystatus(struct mpc52xx_blockata_priv *priv) -+{ -+ return read_altstatus(priv); -+} -+ -+static inline int wait_not_busy(struct mpc52xx_blockata_priv *priv) -+{ -+ int timeout; -+ u8 status; -+ -+ timeout = WAIT_TIMEOUT; -+ -+ status = read_mystatus(priv); -+ if ( ATASTS_IS_NOTBUSY(status) ) -+ goto end; -+ -+ while(timeout--) { -+ status = read_mystatus(priv); -+ if ( ATASTS_IS_NOTBUSY(status) ) -+ goto end; -+ -+ ata_sleep2(priv); -+ } -+ -+ NPRINTK("%s: timeout, %x\n", __func__, status); -+ -+ return -1; -+ -+end: -+ return 0; -+} -+ -+ -+static inline int wait_ready(struct mpc52xx_blockata_priv *priv) -+{ -+ int timeout; -+ u8 status; -+ -+ timeout = WAIT_TIMEOUT; -+ -+ status = read_mystatus(priv); -+ if ( ATASTS_IS_READY(status) ) -+ goto end; -+ -+ while(timeout--) { -+ status = read_mystatus(priv); -+ if ( ATASTS_IS_READY(status) ) -+ goto end; -+ -+ ata_sleep2(priv); -+ } -+ -+ NPRINTK("%s: timeout, %x\n", __func__, status); -+ -+ return -1; -+ -+end: -+ return ATASTS_GOT_ERR(status) ? -1 : 0; -+} -+ -+static inline int wait_drq(struct mpc52xx_blockata_priv *priv) -+{ -+ int timeout; -+ u8 status; -+ -+ timeout = WAIT_TIMEOUT; -+ -+ status = read_mystatus(priv); -+ if ( ATASTS_IS_DRQ(status) ) -+ goto end; -+ -+ while(timeout--) { -+ status = read_mystatus(priv); -+ if ( ATASTS_IS_DRQ(status) ) -+ goto end; -+ -+ ata_sleep2(priv); -+ } -+ -+ NPRINTK("%s: timeout, %x\n", __func__, status); -+ return -1; -+ -+end: -+ return ATASTS_GOT_ERR(status) ? -1 : 0; -+} -+ -+#endif -diff --git a/drivers/block/mpc52xx/protos.h b/drivers/block/mpc52xx/protos.h -new file mode 100644 -index 0000000..aaee5b6 ---- /dev/null -+++ b/drivers/block/mpc52xx/protos.h -@@ -0,0 +1,107 @@ -+/* -+ * protos.h -+ * -+ * Copyright 2006 bplan GmbH -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file "COPYING" in the main directory of this archive -+ * for more details. -+ */ -+ -+ -+/* -+ * Simply summaries every protos we use over the driver -+*/ -+ -+#ifndef __MPC52xx_BLOCKATA_PROTOS_H__ -+#define __MPC52xx_BLOCKATA_PROTOS_H__ -+ -+#include -+#include -+#include -+ -+struct mpc52xx_blockata_priv; -+ -+/**********/ -+/* HWMISC */ -+/**********/ -+int mpc52xx_ata_setpiomode(struct mpc52xx_blockata_priv *priv, int pio_mode); -+int mpc52xx_ata_init_drive(struct mpc52xx_blockata_priv *priv); -+int mpc52xx_ata_isthispiovalid(struct mpc52xx_blockata_priv *priv, int pio_arg); -+int mpc52xx_ata_doidentify(struct mpc52xx_blockata_priv *priv); -+u32 mpc52xx_ata_getregisterbase(struct mpc52xx_blockata_priv *priv); -+int mpx52xx_ata_dosetmulti(struct mpc52xx_blockata_priv *priv, u16 val); -+ -+ -+/**********/ -+/* ATA */ -+/**********/ -+int mpc52xx_ata_setupsector(struct mpc52xx_blockata_priv *priv, sector_t sector, int sector_num, int is_write); -+int mpc52xx_ata_isthispiovalid(struct mpc52xx_blockata_priv *priv, int pio_arg); -+void mpc52xx_ata_dumpreg(struct mpc52xx_blockata_priv *priv); -+int mpc52xx_ata_doreset(struct mpc52xx_blockata_priv *priv); -+int mpc52xx_ata_regcheck(struct mpc52xx_blockata_priv *priv); -+int mpc52xx_ata_dodrivereset(struct mpc52xx_blockata_priv *priv); -+ -+/************/ -+/*DODRIVECMD*/ -+/************/ -+int mpc52xx_ata_dodrivecmd( -+ struct mpc52xx_blockata_priv *priv, -+ unsigned long *irqflags, -+ u8 *arg); -+ -+#ifdef CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA -+ -+ -+/**********/ -+/* SDMA */ -+/**********/ -+int mpc52xx_ata_sdma_setup(struct mpc52xx_blockata_priv *priv); -+ -+void sdma_ata_rx_init(struct bestcomm_taskhandle *mytaskhandle); -+void sdma_ata_tx_init(struct bestcomm_taskhandle *mytaskhandle); -+void sdma_ata_reset(struct bestcomm_taskhandle *mytaskhandle); -+int sdma_ata_getirq(struct bestcomm_taskhandle *mytaskhandle); -+void sdma_ata_clear_irq(struct bestcomm_taskhandle *mytaskhandle); -+void sdma_ata_disable(struct bestcomm_taskhandle *mytaskhandle); -+void sdma_ata_enable(struct bestcomm_taskhandle *mytaskhandle); -+ -+void sdma_ata_submit_buffer( -+ struct bestcomm_taskhandle *mytaskhandle, -+ void *cookie, -+ void *data1, -+ void *data2, -+ int length); -+ -+#endif /* CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA */ -+ -+/**********/ -+/*TRANSFER*/ -+/**********/ -+int mpc52xx_ata_docpupollread( -+ struct mpc52xx_blockata_priv *priv, -+ void *buffer, -+ int len); -+ -+int mpc52xx_ata_docpupollwrite( -+ struct mpc52xx_blockata_priv*priv, -+ void *buffer, -+ int len); -+ -+int mpc52xx_ata_dotransfer( -+ struct mpc52xx_blockata_priv *priv, -+ struct request *req, -+ struct bio *bio, -+ int bio_index, -+ sector_t sector, -+ int sectorcnt, -+ char *buffer, -+ int is_write); -+ -+irqreturn_t sdma_void_handler(struct mpc52xx_blockata_priv *priv); -+irqreturn_t ata_void_handler(struct mpc52xx_blockata_priv *priv, u8 ata_status); -+ -+void mpc52xx_ata_ack_blkreq(struct mpc52xx_blockata_priv *priv, int retval); -+ -+#endif -diff --git a/drivers/block/mpc52xx/sdmatask.c b/drivers/block/mpc52xx/sdmatask.c -new file mode 100644 -index 0000000..eb321e8 ---- /dev/null -+++ b/drivers/block/mpc52xx/sdmatask.c -@@ -0,0 +1,142 @@ -+/* -+ * mpc52xx_atablock / piofunc.c -+ * -+ * Copyright 2006 bplan GmbH -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file "COPYING" in the main directory of this archive -+ * for more details. -+ */ -+ -+ -+/**************/ -+/**************/ -+/**************/ -+ -+#include "mpc52xx_blockata.h" -+ -+ -+/**************/ -+/**************/ -+/**************/ -+ -+ -+#ifdef CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA -+ -+#include -+ -+/**************/ -+/**************/ -+/**************/ -+ -+/**************/ -+void sdma_ata_rx_init(struct bestcomm_taskhandle *mytaskhandle) -+{ -+ struct sdma_ata_inc *inc; -+ inc = (struct sdma_ata_inc *)bestcomm_taskget_inctable(mytaskhandle); -+ -+ NPRINTK("inc = %p\n", inc); -+ -+ inc->incr_bytes = -(s16)sizeof(u16); -+ inc->incr_src = 0; -+ inc->incr_dst = sizeof(u16); -+} -+ -+/**************/ -+/* -+ * Initialize ATA transmit task. -+ */ -+void sdma_ata_tx_init(struct bestcomm_taskhandle *mytaskhandle) -+{ -+ struct sdma_ata_inc *inc; -+ inc = (struct sdma_ata_inc *)bestcomm_taskget_inctable(mytaskhandle); -+ -+ NPRINTK("inc = %p\n", inc); -+ -+ inc->incr_bytes = -(s16)sizeof(u16); -+ inc->incr_src = sizeof(u16); -+ inc->incr_dst = 0; -+} -+ -+/**************/ -+void sdma_ata_reset(struct bestcomm_taskhandle *mytaskhandle) -+{ -+ struct sdma_ata_var *var; -+ var = (struct sdma_ata_var *)bestcomm_taskget_vartable(mytaskhandle); -+ -+ NPRINTK("var = %p\n", var); -+ -+ sdma_reset_buffers2((struct sdma *) mytaskhandle); -+ -+ var->bd_start = var->bd_base; -+} -+ -+ -+/**************/ -+int sdma_ata_getirq(struct bestcomm_taskhandle *mytaskhandle) -+{ -+ return bestcomm_taskget_irq(mytaskhandle); -+} -+ -+/**************/ -+void sdma_ata_clear_irq(struct bestcomm_taskhandle *mytaskhandle) -+{ -+ bestcomm_taskclear_irq(mytaskhandle); -+} -+ -+/**************/ -+void sdma_ata_disable(struct bestcomm_taskhandle *mytaskhandle) -+{ -+ bestcomm_taskdisable(mytaskhandle); -+} -+ -+/**************/ -+void sdma_ata_enable(struct bestcomm_taskhandle *mytaskhandle) -+{ -+ bestcomm_taskenable(mytaskhandle); -+} -+ -+int mpc52xx_ata_sdma_setup(struct mpc52xx_blockata_priv *priv) -+{ -+ struct sdma *s; -+ -+ s = sdma_ata_preinit(MAX_DMA_BUFFERS); -+ if (!s) -+ return -1; -+ -+ priv->sdma = (struct bestcomm_taskhandle *)s; -+ return sdma_ata_init((struct bestcomm_taskhandle *)s, MAX_DMA_BUFFER_SIZE); -+} -+ -+/**************/ -+void sdma_ata_submit_buffer( -+ struct bestcomm_taskhandle *mytaskhandle, -+ void *cookie, -+ void *data1, -+ void *data2, -+ int length) -+{ -+ NPRINTK(" d1=%p, d2=%p, len=%d\n", data1, data2, length); -+ -+ sdma_submit_buffer2( -+ (struct sdma *)mytaskhandle, -+ cookie, data1, data2, length); -+} -+ -+/* -+ * Export stuff -+*/ -+ -+EXPORT_SYMBOL(sdma_ata_rx_init); -+EXPORT_SYMBOL(sdma_ata_tx_init); -+EXPORT_SYMBOL(sdma_ata_disable); -+EXPORT_SYMBOL(sdma_ata_enable); -+EXPORT_SYMBOL(sdma_ata_submit_buffer); -+EXPORT_SYMBOL(sdma_ata_reset); -+EXPORT_SYMBOL(sdma_ata_getirq); -+EXPORT_SYMBOL(sdma_ata_clear_irq); -+EXPORT_SYMBOL(mpc52xx_ata_sdma_setup); -+ -+ -+#endif // CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA -+ -diff --git a/drivers/block/mpc52xx/skel.c b/drivers/block/mpc52xx/skel.c -new file mode 100644 -index 0000000..85b20ad ---- /dev/null -+++ b/drivers/block/mpc52xx/skel.c -@@ -0,0 +1,1024 @@ -+/* -+ * mpc52xx.c -+ * -+ * Copyright 2006 bplan GmbH -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file "COPYING" in the main directory of this archive -+ * for more details. -+ */ -+ -+/* -+ * Here we "translate" Linux API mess to our funcs -+*/ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/**************/ -+/**************/ -+/**************/ -+#include "mpc52xx_blockata.h" -+ -+/**************/ -+/**************/ -+/**************/ -+static int local_setpiomode(struct mpc52xx_blockata_priv *priv, int piomode_arg); -+ -+/**************/ -+/**************/ -+/**************/ -+ -+static void dump_config(struct mpc52xx_blockata_priv *priv) -+{ -+ VPRINTK(" configuration:\n"); -+ -+ if (priv->multi_available) -+ VPRINTK("\t * Multi-PIO commands: available (%d sectors per shot)\n", priv->multi_secpercmd ); -+ VPRINTK("\t * PIO Mode: %d\n", priv->piomode < 0 ? 0 : priv->piomode); -+ -+ if (priv->UsePacket) -+ VPRINTK("\t * Packet feature set supported\n"); -+ -+ if (priv->IsATAPI) -+ VPRINTK("\t * %s ATAPI device detected\n", priv->IsRemovable ? "Removable" : ""); -+ -+ VPRINTK("\t * LBA48 supported: %s\n", priv->drive_canlba48 ? "Yes" : "No"); -+ VPRINTK("\t * CHS: %s (%d/%d/%d)\n", priv->drive_chs_ok ? "Ok" : "Ko", priv->drive_chs_cylinders, priv->drive_chs_heads , priv->drive_chs_sectorspertrack); -+ VPRINTK("\t * SDMA Engine: %s\n", -+#ifdef CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA -+ "Enable"); -+#else -+ "Disable" -+ ); -+#endif -+} -+ -+/**************/ -+/**************/ -+/**************/ -+ -+ -+ -+/* ATAPI-4 PIO specs (arranged for the 5200, cfr User Manual) */ -+/* numbers in ns, extrapolation done by code */ -+static int ataspec_t0[5] = {600, 383, 240, 180, 120}; -+static int ataspec_t1[5] = { 70, 50, 30, 30, 25}; -+static int ataspec_t2_8[5] = {290, 290, 290, 80, 70}; -+static int ataspec_t2_16[5] = {165, 125, 100, 80, 70}; -+static int ataspec_t2i[5] = { 0, 0, 0, 70, 25}; -+static int ataspec_t4[5] = { 30, 20, 15, 10, 10}; -+static int ataspec_ta[5] = { 35, 35, 35, 35, 35}; -+ -+ -+ -+/**************/ -+/**************/ -+/**************/ -+static int device_handlebio( -+ struct mpc52xx_blockata_priv *priv, -+ struct request *req, -+ struct bio *bio, -+ int *sectorcnt_ptr) -+{ -+ int i; -+ struct bio_vec *bvec; -+ sector_t sector; -+ int sectorcnt_biovec; -+ int sectorcnt; -+ int is_write; -+ int ret; -+ -+ ret = -1; -+ is_write = bio_data_dir(bio); -+ sector = bio_getsector(bio); -+ -+ sectorcnt = 0; -+ -+ NPRINTK("bio=%p\n", bio); -+ -+ bio_for_each_segment(bvec, bio, i) -+ { -+ char *buffer; -+ -+ sectorcnt_biovec = bio_cur_sectors_idx(bio, i); -+ buffer = __bio_kmap_atomic(bio, i, KM_USER0); -+ ret = mpc52xx_ata_dotransfer( -+ priv, -+ req, bio, i, -+ sector, sectorcnt_biovec, -+ buffer, is_write); -+ -+ if (ret==0) -+ goto end; -+ -+ // Success or error, we kunmap the buffer -> it's done! -+ __bio_kunmap_atomic(buffer, KM_USER0); -+ -+ if (ret<0) -+ goto end; -+ -+ /* Ret > 0 -> done, do the next one */ -+ sector += ret; -+ sectorcnt += ret; -+ } -+ -+ ret = sector; -+ -+end: -+ *sectorcnt_ptr = sectorcnt; -+ return ret; -+} -+ -+/**************/ -+/**************/ -+/**************/ -+/* -+ * The main challenge! -+*/ -+ -+static int device_handlereq( -+ struct mpc52xx_blockata_priv *priv, -+ struct request *req, -+ int *sectorcnt_ptr) -+{ -+ struct bio *bio; -+ int ret; -+ int nsect; -+ int nsect_thisbio; -+ -+ ret = 0; -+ nsect = 0; -+ -+ if (priv->UsePacket) -+ return -ENOTSUPP; -+ -+ if (priv->io_inprogress) -+ { -+ VPRINTK("IO already in-progress, can not do more!\n"); -+ ret = -EBUSY; -+ goto end; -+ } -+ -+ -+ rq_for_each_bio(bio, req) -+ { -+ ret = device_handlebio(priv, req, bio, &nsect_thisbio); -+ -+ if (ret<=0) -+ goto end; -+ -+ nsect += nsect_thisbio; -+ } -+ -+ ret = nsect; -+ -+end: -+ *sectorcnt_ptr = nsect; -+ return ret; -+} -+ -+/**************/ -+static void device_request(request_queue_t *q) -+{ -+ struct mpc52xx_blockata_priv *priv = (struct mpc52xx_blockata_priv *) q->queuedata; -+ struct request *req; -+ int ret=0; -+ int sectorcnt; -+ -+ while ((req = elv_next_request(q)) != NULL) { -+ -+ if (! blk_fs_request(req)) { -+ printk (KERN_NOTICE "Skip non-fs request\n"); -+ end_request(req, 0); -+ continue; -+ } -+ -+ ret = device_handlereq(priv, req, §orcnt); -+ if (ret==0) { -+ NPRINTK("stop the queue\n"); -+ blk_stop_queue(q); -+ break; -+ } else if (ret>0) -+ end_request(req, 1); -+ else -+ end_request(req, 0); -+ } -+ -+ NPRINTK("end, ret=%d\n", ret); -+} -+ -+ -+/**************/ -+/**************/ -+/**************/ -+ -+static int device_doreset( -+ struct mpc52xx_blockata_priv *priv, -+ int do_drivereset) -+{ -+ int ret = 0; -+ -+ NPRINTK("priv->io_inprogress = %d, do_drivereset=%d\n", -+ priv->io_inprogress, do_drivereset ); -+ -+ if (priv->io_inprogress != 0) -+ mpc52xx_ata_ack_blkreq(priv, 0); -+ -+ ret = mpc52xx_ata_doreset(priv); -+ if(ret<0) -+ ret = -EIO; -+ -+ return ret; -+} -+ -+/* -+ * The device open/close func -+*/ -+ -+/**************/ -+static int device_open(struct inode *inode, struct file *filp) -+{ -+ unsigned long flags; -+ struct mpc52xx_blockata_priv *priv = inode->i_bdev->bd_disk->private_data; -+ int ret = 0; -+ int force_enableirq; -+ -+ NPRINTK("enter. sectors=%lld, usercnt=%d\n", priv->drive_sectors, priv->usercnt); -+ -+ spin_lock_irqsave(&priv->lock, flags); -+ force_enableirq = 0; -+ -+ if (priv->usercnt >= DEVICE_USERLIMIT) -+ { -+ VPRINTK("Error! Too much openers (%d)!\n", priv->usercnt); -+ ret = -1; -+ goto end; -+ } -+ -+ // device not inited ? -> try to init it a gain -+ if (!priv->drive_inited) -+ { -+ priv->drive_sectors = 0; -+ priv->drive_inited = 0; -+ -+ ret = mpc52xx_ata_init_drive(priv); -+ if (ret>=0) -+ priv->drive_inited = 1; -+ -+ ret = 0; -+ } -+ -+ NPRINTK("drive inited ok. s=%x, ret=%d\n", read_altstatus(priv), ret); -+ NPRINTK("drive looks ok. s=%x\n", read_altstatus(priv)); -+ -+ if ( (priv->usercnt==0) || force_enableirq ) -+ { -+ priv->ata_handler = ata_void_handler; -+ priv->sdma_handler = sdma_void_handler; -+ -+ write_ctl(priv, 0); -+ -+ priv->curio_bio = NULL; -+ priv->curio_req = NULL; -+ priv->io_inprogress = 0; -+ } -+ -+ priv->usercnt++; -+ -+end: -+ spin_unlock_irqrestore(&priv->lock, flags); -+ -+ NPRINTK("end. ret=%d\n", ret); -+ return ret; -+} -+ -+/**************/ -+static int device_release(struct inode *inode, struct file *filp) -+{ -+ unsigned long flags; -+ int ret; -+ struct mpc52xx_blockata_priv *priv = inode->i_bdev->bd_disk->private_data; -+ -+ ret = 0; -+ -+ NPRINTK("enter usercnt=%d\n", priv->usercnt); -+ -+ spin_lock_irqsave(&priv->lock, flags); -+ priv->usercnt--; -+ -+ if (priv->usercnt==0) -+ { -+ write_ctl(priv, ATA_NIEN); -+ -+#ifdef CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA -+ sdma_ata_disable(priv->sdma); -+ sdma_ata_clear_irq(priv->sdma); -+ sdma_ata_reset(priv->sdma); -+#endif -+ } -+ -+ if (priv->usercnt<0) -+ VPRINTK("Warning! _release and _open count doesn't match!\n"); -+ -+ NPRINTK("end, ret=%d\n", ret); -+ -+ spin_unlock_irqrestore(&priv->lock, flags); -+ -+ return ret; -+} -+ -+/**************/ -+/**************/ -+/**************/ -+/* -+ * The device ioctl -+*/ -+ -+#ifndef HDIO_GETGEO_BIG -+ -+/* -+ * Let's define GETGEO big because it's used! -+ * they removed it from recent linux kernel -+ * but already compiled software use it (eg: hdparm) -+ * -+ * this define and struct has been picked from linux 2.4.32 -+*/ -+ -+#define HDIO_GETGEO_BIG 0x330 -+struct hd_big_geometry -+{ -+ unsigned char heads; -+ unsigned char sectors; -+ unsigned int cylinders; -+ unsigned long start; -+}; -+#endif -+ -+static int device_ioctl( -+ struct inode *inode, -+ struct file *filp, -+ unsigned int cmd, -+ unsigned long arg) -+{ -+ int ret; -+ unsigned long flags; -+ struct mpc52xx_blockata_priv *priv = inode->i_bdev->bd_disk->private_data; -+ -+ NPRINTK("%s: cmd=0x%x\n", __func__, cmd); -+ -+ spin_lock_irqsave(&priv->lock, flags); -+ -+ switch(cmd) -+ { -+ case HDIO_SET_MULTCOUNT: { -+ u16 multicount; -+ -+ NPRINTK("HDIO_SET_PIO_MODE. Try to set the multicount value to %ld\n", arg); -+ -+ if (priv->UsePacket) { -+ ret = -EIO; -+ break; -+ } -+ -+ multicount = (u16) arg; -+ -+ ret = mpx52xx_ata_dosetmulti(priv, multicount); -+ if (ret<0) -+ ret = -EFAULT; -+ } -+ break; -+ -+ case HDIO_GET_MULTCOUNT: -+ if (priv->UsePacket) { -+ ret = -EIO; -+ break; -+ } -+ -+ ret = put_user(priv->multi_secpercmd , (long __user *) arg); -+ break; -+ -+ case HDIO_DRIVE_CMD: { -+ u8 drivecmd_args[4+512]; -+ u8 drivecmd; -+ int lentocopy; -+ -+ if (NULL == (void *)arg) { -+ ret = -EINVAL; -+ break; -+ } -+ -+ if (copy_from_user(drivecmd_args, (void __user *) arg, sizeof(drivecmd_args) )) { -+ ret = -EFAULT; -+ break; -+ } -+ -+ drivecmd = drivecmd_args[0]; -+ ret = mpc52xx_ata_dodrivecmd(priv, &flags, drivecmd_args); -+ -+ lentocopy = -+ ( (drivecmd==ATA_CMD_ID_ATAPI) || (drivecmd==ATA_CMD_ID_ATA) ) -+ ? (512 + 4): 4; -+ -+ if (copy_to_user((void __user *)arg, drivecmd_args, lentocopy)) -+ ret = -EFAULT; -+ } -+ break; -+ -+ case HDIO_SET_PIO_MODE: { -+ int piomode; -+ NPRINTK("HDIO_SET_PIO_MODE. Try to set PIO %ld\n", arg); -+ -+ if (priv->io_inprogress) { -+ VPRINTK("IO already in-progress, can not do more!\n"); -+ ret = -EBUSY; -+ break; -+ } -+ -+ priv->io_inprogress = 1; -+ piomode = local_setpiomode(priv, (int) arg); -+ priv->io_inprogress = 0; -+ -+ if (piomode>0) -+ VPRINTK("PIO mode %d sat\n", piomode); -+ -+ ret = 0; -+ } -+ break; -+ -+ case HDIO_GET_IDENTITY: { -+ NPRINTK("HDIO_GET_IDENTITY:\n" ); -+ -+ if (priv->drive_identify_valid) { -+ if (copy_to_user((void __user *) arg, priv->drive_identify, sizeof(priv->drive_identify) )) -+ ret = -EFAULT; -+ else -+ ret = 0; -+ } else -+ ret = -1; -+ } -+ break; -+ -+ case HDIO_GETGEO: { -+ struct hd_geometry geo; -+ -+ NPRINTK("HDIO_GETGEO\n"); -+ -+ geo.cylinders = priv->drive_cylinders; -+ geo.heads = priv->drive_heads; -+ geo.sectors = priv->drive_sectorspertrack; -+ geo.start = 0; -+ if (copy_to_user((void __user *) arg, &geo, sizeof(geo))) -+ ret = -EFAULT; -+ else -+ ret = 0; -+ -+ NPRINTK("HDIO_GETGEO, ret=%d\n", ret); -+ } -+ break; -+ -+ case HDIO_GETGEO_BIG: { -+ struct hd_big_geometry biggeo; -+ -+ NPRINTK("HDIO_GETGEO_BIG\n"); -+ -+ biggeo.cylinders = priv->drive_cylinders; -+ biggeo.heads = priv->drive_heads; -+ biggeo.sectors = priv->drive_sectorspertrack; -+ biggeo.start = 0; -+ -+ if (copy_to_user((void __user *) arg, &biggeo, sizeof(biggeo))) -+ ret = -EFAULT; -+ else -+ ret = 0; -+ -+ NPRINTK("HDIO_GETGEO_BIG, ret=%d\n", ret); -+ } -+ break; -+ -+ case HDIO_DRIVE_RESET: { -+ VPRINTK("Issue a controller and drive reset\n"); -+ ret = device_doreset(priv, 1); -+ if(ret<0) -+ ret = -EIO; -+ -+ break; -+ } -+ -+ default: -+ ret = -EINVAL; -+ } -+ -+ NPRINTK("%s: end, ret=%d\n", __func__, ret); -+ -+ spin_unlock_irqrestore(&priv->lock, flags); -+ -+ return ret; -+} -+ -+/**************/ -+/**************/ -+/**************/ -+/* -+ * The device media changes/revalidate -+*/ -+static int device_media_changed(struct gendisk *gd) -+{ -+ /* Our media won't move! */ -+ NPRINTK("\n"); -+ return 0; -+} -+ -+static int device_revalidate_disk(struct gendisk *gd) -+{ -+ NPRINTK("\n"); -+ return 0; -+} -+ -+/**************/ -+/**************/ -+/**************/ -+/* -+ * Modules prove/init -+*/ -+ -+static struct block_device_operations device_fops = -+ { -+ .owner = THIS_MODULE, -+ .open = device_open, -+ .release = device_release, -+ .ioctl = device_ioctl, -+ .media_changed = device_media_changed, -+ .revalidate_disk = device_revalidate_disk, -+ }; -+ -+/**************/ -+static void module_free(struct mpc52xx_blockata_priv *priv) -+{ -+ NPRINTK("Enter. priv=%p\n", priv); -+ if (priv) -+ { -+ NPRINTK("free private private\n"); -+ -+ if (priv->ata_irq>=0) -+ free_irq(priv->ata_irq, priv); -+ -+#ifdef CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA -+ if (priv->sdma_irq>=0) -+ free_irq(priv->sdma_irq, priv); -+#endif -+ -+ NPRINTK("priv->device_queue=%p\n", priv->device_queue); -+ if (priv->device_queue) -+ blk_cleanup_queue(priv->device_queue); -+ -+ NPRINTK("priv->device_gendisk=%p\n", priv->device_gendisk); -+ if (priv->device_gendisk) -+ del_gendisk(priv->device_gendisk); -+ -+ NPRINTK("priv->major=%d\n", priv->major); -+ if (priv->major>0) -+ unregister_blkdev(priv->major, DEVSKEL_DEVICENAME); -+ -+ NPRINTK("free priv. p=%p\n", priv); -+ kfree(priv); -+ } -+ -+ NPRINTK("End\n"); -+} -+ -+static void module_remove(struct mpc52xx_blockata_priv *priv) -+{ -+ printk(KERN_INFO DEVSKEL_DRIVERNAME ": Tchuss!\n"); -+ module_free(priv); -+} -+ -+ -+ -+/**************/ -+/**************/ -+/**************/ -+ -+#ifdef CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA -+ -+irqreturn_t generalsdma_handler(int irq, void *host) -+ { -+ struct mpc52xx_blockata_priv *priv = (struct mpc52xx_blockata_priv *) host; -+ irqreturn_t ret = IRQ_NONE; -+ -+ NPRINTK2("%s: irq=%d, sdma_handler %p\n", __func__, irq, priv->sdma_handler); -+ -+ if (irq == priv->sdma_irq) -+ { -+ ret = -+ (priv->sdma_handler) -+ ? priv->sdma_handler(priv) -+ : IRQ_HANDLED; -+ } else -+ { -+ ret = IRQ_NONE; -+ } -+ -+ return ret; -+ } -+ -+ -+#endif -+ -+ irqreturn_t generalata_handler(int irq, void *host) -+ { -+ struct mpc52xx_blockata_priv *priv = (struct mpc52xx_blockata_priv *) host; -+ irqreturn_t ret; -+ -+ if (irq == priv->ata_irq) -+ { -+ u8 status; -+ status = read_status(priv); -+ -+ ret = -+ (priv->ata_handler) -+ ? priv->ata_handler(priv, status) -+ : IRQ_HANDLED; -+ } else -+ { -+ ret = IRQ_NONE; -+ } -+ -+ return ret; -+ } -+ -+ -+ static void -+ mpc52xx_ide_apply_timing(struct mpc52xx_ata __iomem *regs, struct mpc52xx_ata_timings *timing) -+ { -+ out_be32(®s->pio1, timing->pio1); -+ out_be32(®s->pio2, timing->pio2); -+ out_be32(®s->mdma1, timing->mdma1); -+ out_be32(®s->mdma2, timing->mdma2); -+ out_be32(®s->udma1, timing->udma1); -+ out_be32(®s->udma2, timing->udma2); -+ out_be32(®s->udma3, timing->udma3); -+ out_be32(®s->udma4, timing->udma4); -+ out_be32(®s->udma5, timing->udma5); -+ } -+ -+ static void -+ mpc52xx_ide_compute_pio_timing( struct mpc52xx_ata_timings *timing, unsigned int ipb_period, u8 pio) -+ { -+ u32 t0, t2_8, t2_16, t2i, t4, t1, ta; -+ -+ /* We add 1 as a 'margin' */ -+ t0 = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_t0[pio]); -+ t2_8 = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_t2_8[pio]); -+ t2_16 = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_t2_16[pio]); -+ t2i = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_t2i[pio]); -+ t4 = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_t4[pio]); -+ t1 = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_t1[pio]); -+ ta = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_ta[pio]); -+ -+ timing->pio1 = (t0 << 24) | (t2_8 << 16) | (t2_16 << 8) | (t2i); -+ timing->pio2 = (t4 << 24) | (t1 << 16) | (ta << 8); -+ } -+ -+ static int local_setpiomode(struct mpc52xx_blockata_priv *priv, int piomode_arg) -+ { -+ int piomode; -+ int ret; -+ -+ NPRINTK(KERN_DEBUG DEVSKEL_DEVICENAME "pio mode arg=%d\n", piomode_arg); -+ -+ piomode = mpc52xx_ata_isthispiovalid(priv, piomode_arg); -+ if (piomode<0) -+ return -1; -+ -+ NPRINTK(KERN_DEBUG DEVSKEL_DEVICENAME "pio mode=%d\n", piomode); -+ -+ ret = mpc52xx_ata_setpiomode(priv, piomode); -+ if (ret<0) -+ return -1; -+ -+ mpc52xx_ide_compute_pio_timing(&priv->timings[0], priv->ipb_period, piomode); -+ mpc52xx_ide_apply_timing(priv->ata_regs, &priv->timings[0]); -+ -+ return piomode; -+ } -+ -+ static int -+ mpc52xx_ide_setup( -+ struct mpc52xx_ata __iomem *regs, -+ struct mpc52xx_blockata_priv *priv) -+ { -+ -+#define MPC52xx_IPBFREQ (132*1000*1000) -+ -+ /* Vars */ -+ -+ int tslot; -+ -+ NPRINTK("%s: enter\n", __func__); -+ -+ out_8(®s->dma_mode, MPC52xx_ATA_DMAMODE_FR); -+ udelay(10); -+ -+ /* All sample code do this */ -+ out_be32(®s->share_cnt, 0); -+ -+ /* Configure & Reset host */ -+ out_be32(®s->config, -+ MPC52xx_ATA_HOSTCONF_IE | -+ MPC52xx_ATA_HOSTCONF_IORDY | -+ MPC52xx_ATA_HOSTCONF_SMR | -+ MPC52xx_ATA_HOSTCONF_FR); -+ udelay(10); -+ out_be32(®s->config, -+ MPC52xx_ATA_HOSTCONF_IE | -+ MPC52xx_ATA_HOSTCONF_IORDY); -+ -+ /* Get IPB bus period */ -+ priv->ipb_period = 1000000000 / (MPC52xx_IPBFREQ/1000); -+ -+ /* Try to set the time slot to around 1us = 1000000 ps */ -+ tslot = CALC_CLK_VALUE_UP(priv->ipb_period, 1000000); -+ out_be32(®s->share_cnt, tslot << 16); -+ -+ -+ /* Init imings to PIO0 (safest) */ -+ memset(priv->timings, 0x00, 2*sizeof(struct mpc52xx_ata_timings)); -+ -+ mpc52xx_ide_compute_pio_timing(&priv->timings[0], priv->ipb_period, 0); -+ mpc52xx_ide_compute_pio_timing(&priv->timings[1], priv->ipb_period, 0); -+ -+ mpc52xx_ide_apply_timing(regs, &priv->timings[0]); -+ -+ return 0; -+ } -+ -+ -+ -+ -+ static int some_hwinit(struct mpc52xx_blockata_priv *priv) -+ { -+ struct mpc52xx_gpio __iomem *gpio_regs; -+ struct mpc52xx_ata __iomem *ata_regs; -+ struct device_node *of_dev; -+ int ata_irq; -+ u32 res_mem; -+ int sdma_irqnum; -+ int ret; -+ -+ ata_irq = -1; -+ sdma_irqnum = -1; -+ -+ ata_regs = NULL; -+ gpio_regs = NULL; -+ res_mem = 0; -+ -+ -+ -+ priv->ata_irq = -1; -+ priv->sdma_irq = -1; -+ -+ of_dev = of_find_compatible_node(NULL, "ata", "mpc5200-ata"); -+ if (of_dev == NULL) -+ return -ENODEV; -+ -+ -+ /* Get the resources of this device */ -+ ata_irq = irq_of_parse_and_map(of_dev, 0); -+ if (ata_irq<0) -+ { -+ printk(KERN_ERR DEVSKEL_DRIVERNAME ": Invalid resource set!\n"); -+ return -EINVAL; -+ } -+ -+ ret = request_irq(ata_irq, generalata_handler, SA_INTERRUPT, DEVSKEL_DRIVERNAME " ATA interrupt", priv); -+ if (ret) -+ { -+ printk(KERN_ERR DEVSKEL_DRIVERNAME ": Can not allocate interrupt for the ATA controller\n"); -+ ata_irq=-1; -+ goto error; -+ } -+ priv->ata_irq = ata_irq; -+ -+ res_mem = mpc52xx_ata_getregisterbase(priv); -+ if (!res_mem) -+ { -+ printk(KERN_ERR DEVSKEL_DRIVERNAME ": Unable to locate ATA registers\n"); -+ ret = -ENOMEM; -+ goto error; -+ } -+ -+ ata_regs = ioremap(res_mem, sizeof(struct mpc52xx_ata)); -+ if (!ata_regs) -+ { -+ printk(KERN_ERR DEVSKEL_DRIVERNAME ": Unable to ioremap ATA registers\n"); -+ ret = -ENOMEM; -+ goto error; -+ } -+ -+ priv->ata_regs = ata_regs; -+ priv->ata_regs_bus = res_mem; -+ -+ /* Setup the ATA controller */ -+ ret = mpc52xx_ide_setup(ata_regs, priv); -+ if (ret) -+ { -+ printk(KERN_ERR DEVSKEL_DRIVERNAME ": Controller setup failed !\n"); -+ goto error; -+ } -+ -+#ifdef CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA -+ ret = mpc52xx_ata_sdma_setup(priv); -+ if (ret) -+ { -+ printk(KERN_ERR DEVSKEL_DRIVERNAME ": SDMA setup failed !\n"); -+ goto error; -+ } -+ -+ sdma_irqnum = sdma_ata_getirq(priv->sdma); -+ ret = request_irq(sdma_irqnum, generalsdma_handler, SA_INTERRUPT, DEVSKEL_DRIVERNAME " SDMA interrupt", priv); -+ if (ret) -+ { -+ printk(KERN_ERR DEVSKEL_DRIVERNAME ": Can not allocate interrupt for the SDMA Task\n"); -+ goto error; -+ } -+ -+ priv->sdma_irq = sdma_irqnum; -+ -+ NPRINTK("%s: ATA irq=%d, SDMA IRQ=%d\n", __func__, ata_irq, priv->sdma_irq); -+ -+#endif -+ -+ return 0; -+ -+ error: -+ return ret; -+ } -+ -+ /**************/ -+ static struct mpc52xx_blockata_priv *module_probe(int *retcode) -+ { -+ int ret; -+ struct mpc52xx_blockata_priv *priv; -+ struct gendisk *device_gendisk; -+ struct request_queue *device_queue; -+ -+ ret = 0; -+ priv = NULL; -+ device_gendisk = NULL; -+ device_queue = NULL; -+ -+ NPRINTK("enter\n"); -+ -+ -+ /* Setup private structure */ -+ priv = kmalloc(sizeof(*priv), GFP_ATOMIC); -+ if (!priv) -+ { -+ printk(KERN_ERR DEVSKEL_DRIVERNAME ": Can't allocate private structure !\n"); -+ ret = -ENOMEM; -+ goto error; -+ } -+ memset(priv, 0, sizeof (*priv) ); -+ -+ -+ spin_lock_init(&priv->lock); -+ priv->major = -1; -+ -+ NPRINTK("device privata data ok. p=%p\n", priv); -+ -+ ret = some_hwinit(priv); -+ if(ret<0) -+ { -+ printk(KERN_ERR DEVSKEL_DRIVERNAME ": Can't allcoate some private stuff !\n"); -+ goto error; -+ } -+ -+ priv->drive_sectors = 0; -+ priv->drive_inited = 0; -+ -+ /* -+ * I prefer to the drive init here. Indeed, in case of failure -+ * (for example no drive present), the linux block code generally exploses -+ * -+ */ -+ ret = mpc52xx_ata_init_drive(priv); -+ if (ret<0) -+ { -+ printk(KERN_ERR DEVSKEL_DRIVERNAME ": Can not init the ATA drive\n"); -+ goto error; -+ } -+ -+ ret = register_blkdev(0, DEVSKEL_DEVICENAME); -+ if (ret<0) -+ { -+ printk(KERN_ERR DEVSKEL_DRIVERNAME ": Can not register the block device\n"); -+ goto error; -+ } -+ priv->major = ret; -+ -+ NPRINTK("block device registered with major %d\n", ret); -+ -+ // minors must be >1 for partition mess (?) -+ device_gendisk = alloc_disk(32); -+ if (!device_gendisk) -+ { -+ printk(KERN_ERR DEVSKEL_DRIVERNAME ": Can not allocate a block disk\n"); -+ goto error; -+ } -+ priv->device_gendisk = device_gendisk; -+ -+ device_gendisk->major = priv->major; -+ device_gendisk->first_minor = 0; -+ device_gendisk->fops = &device_fops; -+ sprintf(device_gendisk->disk_name, DEVSKEL_DEVICENAME); -+ -+ NPRINTK("device disk allocated. p=%p\n", device_gendisk); -+ -+ device_queue = blk_init_queue(device_request, &priv->lock); -+ if (!device_queue) -+ { -+ printk(KERN_ERR DEVSKEL_DRIVERNAME ": Can not init the block queue\n"); -+ ret = -1; -+ goto error; -+ } -+ -+ priv->device_queue = device_queue; -+ device_gendisk->queue = device_queue; -+ -+ NPRINTK("block queue ok. p=%p\n", device_queue); -+ -+ device_queue->queuedata = priv; -+ device_gendisk->private_data = priv; -+ -+ -+#ifdef CONFIG_BLK_DEV_MPC52XX_ATAPIO_MAXPIO -+ NPRINTK("Set pio mode to max\n"); -+ priv->piomode = local_setpiomode( priv, -1); -+#endif -+ -+ priv->drive_inited = 1; -+ -+ /* Only add the disk as very last step */ -+ blk_queue_max_phys_segments(device_queue, DRIVER_MAXHWSEG); -+ blk_queue_max_sectors(priv->device_queue, DRIVER_MAXHWSEG); -+ -+ // This should be the multi pio value -+ blk_queue_max_hw_segments(device_queue, priv->multi_secpercmd); -+ -+ set_capacity(priv->device_gendisk, priv->drive_sectors); -+ add_disk(device_gendisk); -+ -+ init_waitqueue_head(&priv->my_waitqueue); -+ -+ printk(KERN_INFO DEVSKEL_DRIVERNAME ": %s (Version %s - Compiled date %s at %s)\n", DEVSKEL_DRIVERNAME, DEVSKEL_DRIVERVERSION, __DATE__, __TIME__); -+ dump_config(priv); -+ -+ *retcode = 0; -+ return priv; -+ -+ error: -+ -+ module_free(priv); -+ -+ *retcode = (ret == 0) ? -1 : ret; -+ return NULL; -+ } -+ -+ /**************/ -+ /**************/ -+ /**************/ -+ /* -+ * Kernel call for module load/remove -+ */ -+ struct mpc52xx_blockata_priv *global_priv = NULL; -+ -+static int __init kernelcall_init(void) -+{ -+ int retcode; -+ -+ global_priv = module_probe(&retcode); -+ return retcode; -+} -+ -+static void __exit kernelcall_exit(void) -+{ -+ module_remove(global_priv); -+ global_priv = NULL; -+} -+ -+ -+module_init(kernelcall_init); -+module_exit(kernelcall_exit); -+ -+MODULE_AUTHOR("bplan GmbH"); -+MODULE_DESCRIPTION(DEVSKEL_DRIVERNAME); -+MODULE_LICENSE("GPL"); -+ -diff --git a/drivers/block/mpc52xx/transfer.c b/drivers/block/mpc52xx/transfer.c -new file mode 100644 -index 0000000..50f5f3a ---- /dev/null -+++ b/drivers/block/mpc52xx/transfer.c -@@ -0,0 +1,932 @@ -+/* -+ * mpc52xx_atablock / transfer.c -+ * -+ * Copyright 2006 bplan GmbH -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file "COPYING" in the main directory of this archive -+ * for more details. -+ */ -+ -+/* -+ * real brain! -+*/ -+ -+ -+#include "mpc52xx_blockata.h" -+ -+ -+/**************/ -+/**************/ -+/**************/ -+static int ata_dopollwrite( -+ struct mpc52xx_blockata_priv *priv, -+ void *buffer, -+ int len); -+static int ata_dopollread( -+ struct mpc52xx_blockata_priv *priv, -+ void *buffer, -+ int len); -+ -+/**************/ -+/**************/ -+/**************/ -+/* -+ * We could check for unexpected interrupt or status here -+*/ -+ -+irqreturn_t sdma_void_handler(struct mpc52xx_blockata_priv *priv) -+ { -+ NPRINTK("%s: \n", __func__); -+ return IRQ_HANDLED; -+ } -+ -+ irqreturn_t ata_void_handler(struct mpc52xx_blockata_priv *priv, u8 ata_status) -+ { -+ NPRINTK("%s: status=0x%2.2x\n", __func__, ata_status); -+ return IRQ_HANDLED; -+ } -+ -+ -+ -+#ifdef CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA -+ -+ /**************/ -+ static int start_writerequest( -+ struct mpc52xx_blockata_priv *priv, -+ struct request *req, -+ struct bio *bio, -+ int bio_index, -+ sector_t sector, -+ int sectorcnt, -+ u16 * buffer); -+static void submit_writebuffer( -+ struct mpc52xx_blockata_priv *priv, -+ u16 *buffer, -+ int curio_secidx); -+ -+static void submit_readbuffer( -+ struct mpc52xx_blockata_priv *priv, -+ u16 *buffer, -+ int curio_secidx); -+static int submitandenable_readbuffer( -+ struct mpc52xx_blockata_priv *priv, -+ u16 *buffer); -+static int start_readrequest( -+ struct mpc52xx_blockata_priv *priv, -+ struct request *req, -+ struct bio *bio, -+ int bio_index, -+ sector_t sector, -+ int sectorcnt, -+ u16 * buffer); -+ -+/**************/ -+void mpc52xx_ata_ack_blkreq(struct mpc52xx_blockata_priv *priv, int retval) -+{ -+ struct request *req; -+ -+ req = priv->curio_req; -+ -+ priv->curio_bio = NULL; -+ priv->curio_req = NULL; -+ priv->sdma_handler = sdma_void_handler; -+ priv->ata_handler = ata_void_handler; -+ -+ priv->io_inprogress = 0; -+ -+ // Ack the req if any -+ if (req) -+ end_request(req, retval); -+ -+ // Make sure to restart the queue -+ blk_start_queue(priv->device_queue); -+} -+ -+/**************/ -+static int inhandlercheck_atastatus( -+ struct mpc52xx_blockata_priv *priv, -+ u8 ata_status) -+{ -+ if ( ATASTS_GOT_ERR(ata_status) ) -+ { -+ VPRINTK("ATA Error, transfer aborted"); -+ ATA_DUMPREG -+ -+ mpc52xx_ata_ack_blkreq(priv, 0); -+ -+ // taut! -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+/**************/ -+/* -+ * This func will do the necessary operation when a bio iovec is done -+ * -> end the transfer if there are no more job -+ * -> start a new io vec if any -+ * -> start a new bio if any -+ * -+ * This is the same for RX and TX buffer that's why I wrote this static -+ * (and hopefully inlined !) func -+ * -+*/ -+static inline u16 *handle_nextbio( -+ struct mpc52xx_blockata_priv *priv, -+ struct request *req, -+ struct bio **ptr_bio, -+ int *ptr_bio_idx, -+ sector_t *ptr_sector, -+ int *ptr_sectorcnt) -+{ -+ struct bio *bio; -+ int bio_idx; -+ int lastvec_sectorcnt; -+ sector_t sector; -+ -+ bio = priv->curio_bio; -+ -+ // need to do! -+ NPRINTK2(KERN_DEBUG "One iovec done. bio idx=%d. cnt=%d\n", bio->bi_idx, bio->bi_vcnt); -+ -+ /* Unmap the previous one -+ * kmap stuff is a bit strange -+ * the LDD manual pass the bio, but the -+ * macro seen to accept the buffer... -+ * maybe API change between the LDD (3rd release) -+ * and this Linux kernel (2.6.16.15 but also in 2.6.17.1). -+ * anyway, kmap* seens void. -+ */ -+ __bio_kunmap_atomic( bio_data(bio), KM_USER0); -+ -+ bio_idx = priv->curio_bioidx; -+ lastvec_sectorcnt = bio_cur_sectors_idx(bio, bio_idx); -+ -+ bio_idx++; -+ if (bio_islastidx(bio, bio_idx) ) -+ { -+ // Finish with this bio -+ -+ // Let's see if there is another bio in this req -+ bio = bio_getnext(bio); -+ if (!bio) { -+ // we have done! -+ NPRINTK(KERN_DEBUG "req (%p, bio=%p) over, ack it and start the queue\n", -+ req, bio); -+ -+ mpc52xx_ata_ack_blkreq(priv, 1); -+ -+ // vertig -+ return NULL; -+ } -+ -+ NPRINTK(KERN_DEBUG "bio over,but new one %p\n", bio); -+ -+ // Set up stuff for the new bio -+ bio_idx = bio_getcuridx(bio); -+ sector = bio_getsector(bio); -+ } else -+ { -+ // Set up stuff for the next bio iovec -+ NPRINTK(KERN_DEBUG "bio iovec over,but new one %d\n", bio_idx); -+ -+ sector = priv->curio_sector + lastvec_sectorcnt; -+ } -+ -+ *ptr_bio = bio; -+ *ptr_sector = sector; -+ *ptr_bio_idx = bio_idx; -+ *ptr_sectorcnt = bio_cur_sectors_idx(bio, bio_idx); -+ -+ // Small notes, I'm really not sure kmap atomix is smart here -+ // We should prolly use kmap_irq as we will prolly be called from an interrupt -+ return __bio_kmap_atomic(bio, bio_idx, KM_USER0); -+} -+ -+/**************/ -+ -+irqreturn_t ata_complete_txtransfer_handler(struct mpc52xx_blockata_priv *priv, u8 ata_status) -+ { -+ int secidx; -+ int sectodo; -+ int secpershot; -+ u16 *buffer; -+ -+ NPRINTK2("curio_secidx=%d, curio_sectodo=%d. bio=%p, req=%p. s=0x%x\n", -+ priv->curio_secidx, priv->curio_sectodo, priv->curio_bio, priv->curio_req, ata_status ); -+ -+ // Make sure to kill the task first -+ sdma_ata_disable(priv->sdma); -+ -+ // Sanity check! -+ if ( ! priv->io_inprogress ) -+ goto end; -+ -+ if ( inhandlercheck_atastatus(priv, ata_status ) ) -+ goto end; -+ -+ // grab some data -+ secidx = priv->curio_secidx; -+ sectodo = priv->curio_sectodo; -+ secpershot = priv->curio_secpershot; -+ -+ secidx += secpershot; -+ if (secidx < sectodo) -+ { -+ if ( ATASTS_IS_READY(ata_status) ) { -+ // Update the buffer to the position of the new sector to write -+ // buffer is a u16* -+ buffer = ( (u16 *) priv->curio_buffer) + (priv->curio_secpershot * 256); -+ -+ submit_writebuffer(priv, buffer, secidx); -+ -+ sdma_ata_enable(priv->sdma); -+ } else { -+ // Error here, DRQ should be set -+ goto end; -+ } -+ } else -+ { -+ struct bio *bio; -+ struct request *req; -+ int ret; -+ int bio_idx; -+ int sectorcnt; -+ u16 *buffer; -+ sector_t sector; -+ -+ req = priv->curio_req; -+ buffer = handle_nextbio(priv, req, &bio, &bio_idx, §or, §orcnt); -+ -+ ret = -+ buffer -+ ? start_writerequest(priv, req, bio, bio_idx, sector, sectorcnt, buffer) -+ : -1; -+ } -+ -+ end: -+ return IRQ_HANDLED; -+ } -+ -+ -+ -+ /**************/ -+ irqreturn_t sdma_complete_rxtransfer_handler(struct mpc52xx_blockata_priv *priv); -+ -+irqreturn_t ata_wait_rxready_handler(struct mpc52xx_blockata_priv *priv, u8 ata_status) -+ { -+ NPRINTK2("%s: \n", __func__); -+ -+ // Sanity check! -+ if (!priv->io_inprogress) -+ { -+ // Should report some erro rhere! -+ goto end; -+ } -+ -+ if ( inhandlercheck_atastatus(priv, ata_status ) ) -+ goto end; -+ -+ if ( ATASTS_IS_DRQ(ata_status) ) -+ { -+ // Set up the new handlers -+ priv->sdma_handler = sdma_complete_rxtransfer_handler; -+ priv->ata_handler = ata_void_handler; -+ -+ // Now start the transfer -+ submitandenable_readbuffer(priv, priv->curio_buffer); -+ } -+ -+ end: -+ return IRQ_HANDLED; -+ } -+ -+ irqreturn_t sdma_complete_rxtransfer_handler(struct mpc52xx_blockata_priv *priv) -+ { -+ int secidx; -+ int sectodo; -+ int secpershot; -+ u16 *buffer; -+ -+ NPRINTK("curio_secidx=%d, curio_sectodo=%d. bio=%p, req=%p.\n", -+ priv->curio_secidx, priv->curio_sectodo, priv->curio_bio, priv->curio_req ); -+ -+ // Make sure to kill the task first -+ sdma_ata_disable(priv->sdma); -+ -+ // Sanity check! -+ if ( ! priv->io_inprogress ) -+ goto end; -+ -+ // grab -+ secidx = priv->curio_secidx; -+ sectodo = priv->curio_sectodo; -+ secpershot = priv->curio_secpershot; -+ -+ if ( inhandlercheck_atastatus(priv, read_altstatus(priv) ) ) -+ goto end; -+ -+ secidx += secpershot; -+ if (secidx < sectodo) -+ { -+#if 0 -+ u8 ata_status; -+ -+ // Rx transfer for this sector over, wait for intr for the new one -+ priv->sdma_handler = sdma_void_handler; -+ priv->ata_handler = ata_wait_rxready_handler; -+ -+ // reading the status reg should acknowledge this transfer -+ // and start the next one -+ ata_status = read_status(priv); -+#else -+ // Stuff data to transfer for this iovec -+ //if ( IS_READY( read_altstatus(priv) ) ) -+ { -+ buffer = ( (u16 *) priv->curio_buffer) + (secpershot * 256); -+ -+ NPRINTK("%s: ATA ready -> read task started. Sector=%lld\n", __func__, priv->curio_sector); -+ -+ submit_readbuffer(priv, buffer, secidx); -+ -+ // I don't like to wait here -+ wait_drq(priv); -+ sdma_ata_enable(priv->sdma); -+ } -+#endif -+ } else -+ { -+ struct bio *bio; -+ struct request *req; -+ int ret; -+ int bio_idx; -+ int sectorcnt; -+ u16 *buffer; -+ sector_t sector; -+ -+ req = priv->curio_req; -+ buffer = handle_nextbio(priv, req, &bio, &bio_idx, §or, §orcnt); -+ -+ ret = -+ buffer -+ ? start_readrequest(priv, req, bio, bio_idx, sector, sectorcnt, buffer) -+ : -1; -+ } -+ -+ end: -+ return IRQ_HANDLED; -+ } -+ -+ -+ /* -+ * This func will setup the ATA and the SDMA buffers -+ * and install the ATA handler -+ */ -+ /**************/ -+ static void submit_writebuffer( -+ struct mpc52xx_blockata_priv *priv, -+ u16 *buffer, -+ int curio_secidx) -+ { -+ u32 port_BusAddr; -+ u32 addr_BusAddr; -+ -+ port_BusAddr = ATAFIFO_BUSADDR; -+ addr_BusAddr = virt_to_phys( (void*) buffer); -+ -+ NPRINTK("priv=%p, , port bus=0x%8.8x, addr bus =0x%8.8x, buf=%p, idx=%d\n", -+ priv, port_BusAddr, addr_BusAddr, buffer, curio_secidx); -+ -+ // reset the buf -+ sdma_ata_reset(priv->sdma); -+ -+ sdma_ata_submit_buffer( -+ priv->sdma, -+ (void *) buffer, -+ (void *) addr_BusAddr, -+ (void *) port_BusAddr, -+ 512*priv->curio_secpershot); -+ -+ priv->curio_secidx = curio_secidx; -+ priv->curio_buffer = buffer; -+ } -+ -+ -+ static int start_writerequest( -+ struct mpc52xx_blockata_priv *priv, -+ struct request *req, -+ struct bio *bio, -+ int bio_index, -+ sector_t sector, -+ int sectorcnt, -+ u16 *buffer) -+ { -+ -+ int ret; -+ int secperreq; -+ int sectodo; -+ int secpershot; -+ -+ NPRINTK("%s: sector=%ld, sectorcnt=%d, buffer=%p\n", __func__, (long) sector, sectorcnt, buffer); -+ -+ secperreq = priv->multi_secpercmd; -+ sectodo = sectorcnt > secperreq ? secperreq : sectorcnt; -+ secpershot = sectodo ; -+ -+ ret = wait_not_busy(priv); -+ if (ret!=0) -+ return ret; -+ mpc52xx_ata_setupsector(priv, sector, sectodo, 1); -+ -+ // I don't like to call wait here -+ ret = wait_ready(priv); -+ if (ret!=0) -+ { -+ NPRINTK("can't wait rdy=%d. 0x%x\n", ret, read_altstatus(priv)); -+ ATA_DUMPREG -+ return ret; -+ } -+ -+ priv->curio_sector = sector; -+ priv->curio_secpershot = secpershot; -+ priv->curio_sectodo = sectodo; -+ priv->curio_req = req; -+ priv->curio_bio = bio; -+ priv->curio_bioidx = bio_index; -+ -+ priv->sdma_handler = sdma_void_handler; -+ priv->ata_handler = ata_complete_txtransfer_handler; -+ -+ priv->io_inprogress = 1; -+ -+ write_cmd(priv, priv->curio_atacmd); -+ ret = wait_drq(priv); -+ if (ret!=0) -+ { -+ ATA_DUMPREG -+ return ret; -+ } -+ -+ submit_writebuffer(priv, (u16 *) buffer, 0); -+ sdma_ata_enable(priv->sdma); -+ -+ return 0; -+ } -+ -+ -+ /**************/ -+ -+ /**************/ -+ static void submit_readbuffer( -+ struct mpc52xx_blockata_priv *priv, -+ u16 *buffer, -+ int curio_secidx) -+ { -+ u32 port_BusAddr; -+ u32 addr_BusAddr; -+ -+ port_BusAddr = ATAFIFO_BUSADDR; -+ addr_BusAddr = virt_to_phys( (void*) buffer); -+ -+ NPRINTK2("priv=%p, , port bus=0x%8.8x, addr bus =0x%8.8x, buf=%p, idx=%d\n", -+ priv, port_BusAddr, addr_BusAddr, buffer, curio_secidx); -+ -+ // reset the buf -+ sdma_ata_reset(priv->sdma); -+ -+ sdma_ata_submit_buffer( -+ priv->sdma, -+ (void *) buffer, -+ (void *) port_BusAddr, -+ (void *) addr_BusAddr, -+ 512*priv->curio_secpershot); -+ -+ priv->curio_secidx = curio_secidx; -+ priv->curio_buffer = buffer; -+ } -+ -+ static int submitandenable_readbuffer( -+ struct mpc52xx_blockata_priv *priv, -+ u16 *buffer) -+ { -+ -+ submit_readbuffer(priv, (u16 *) buffer, 0); -+ sdma_ata_enable(priv->sdma); -+ -+ return 0; -+ } -+ -+ static int start_readrequest( -+ struct mpc52xx_blockata_priv *priv, -+ struct request *req, -+ struct bio *bio, -+ int bio_index, -+ sector_t sector, -+ int sectorcnt, -+ u16 *buffer) -+ { -+ int ret; -+ int secperreq; -+ int sectodo; -+ int secpershot; -+ -+ NPRINTK2("%s: sector=%ld, sectorcnt=%d, buffer=%p, cmd=0%2.2x\n", __func__, (long) sector, sectorcnt, buffer, priv->curio_atacmd); -+ -+ secperreq = priv->multi_secpercmd; -+ sectodo = sectorcnt > secperreq ? secperreq : sectorcnt; -+ secpershot = sectodo; -+ -+ ret = wait_not_busy(priv); -+ if (ret!=0) -+ return ret; -+ -+ mpc52xx_ata_setupsector(priv, sector, sectodo, 0); -+ -+ ret = wait_ready(priv); -+ if (ret!=0) -+ { -+ NPRINTK("can't wait rdy=%d. 0x%x\n", ret, read_altstatus(priv)); -+ ATA_DUMPREG -+ return ret; -+ } -+ -+ priv->curio_sector = sector; -+ priv->curio_secpershot = secpershot; -+ priv->curio_sectodo = sectodo; -+ priv->curio_req = req; -+ priv->curio_bio = bio; -+ priv->curio_bioidx = bio_index; -+ -+ priv->sdma_handler = sdma_void_handler; -+ priv->ata_handler = ata_wait_rxready_handler; -+ -+ priv->io_inprogress = 1; -+ -+ /* -+ * We only start the task when we got the drive int -+ */ -+ priv->curio_secidx = 0; -+ priv->curio_buffer = buffer; -+ write_cmd(priv, priv->curio_atacmd); -+ -+ return 0; -+ } -+#endif -+ -+ -+ -+#ifndef CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA -+ /**************/ -+ /**************/ -+ /**************/ -+ /* -+ * This do_read func use polling -> not interrupt! -+ */ -+ -+ static int do_readrequest( -+ struct mpc52xx_blockata_priv *priv, -+ struct request *req, -+ struct bio *bio, -+ int bio_index, -+ sector_t sector, -+ int sectorcnt, -+ u16 * buffer) -+ { -+ int ret; -+ int secperreq; -+ int sectodo; -+ int sectorcnt_original = sectorcnt; -+ -+ NPRINTK("%s: sector=%ld, sectorcnt=%d, buffer=%p\n", __func__, (long) sector, sectorcnt, buffer); -+ -+ secperreq = priv->multi_secpercmd; -+ -+ while(sectorcnt>0) -+ { -+ int i; -+ sectodo = sectorcnt > secperreq ? secperreq : sectorcnt; -+ -+ ret = wait_not_busy(priv); -+ if (ret!=0) -+ return -1; -+ mpc52xx_ata_setupsector(priv, sector, sectodo, 0); -+ -+ ret = wait_ready(priv); -+ if (ret!=0) { -+ ATA_DUMPREG -+ return ret; -+ } -+ -+ if (priv->multi_available) { -+ write_cmd(priv, ATA_CMD_READ_MULTI); -+ ret = wait_drq(priv); -+ if (ret!=0) { -+ ATA_DUMPREG -+ return ret; -+ } -+ ret = ata_dopollread(priv, buffer, 256*sectodo ); -+ buffer = ( ((u16*) buffer) + 256*sectodo ); -+ } else { -+ write_cmd(priv, ATA_CMD_PIO_READ); -+ -+ for(i=0; i < sectodo; i++) { -+ ret = wait_drq(priv); -+ if (ret!=0) { -+ ATA_DUMPREG -+ return ret; -+ } -+ -+ ret = ata_dopollread(priv, buffer, 256); -+ -+ // Check! -+ -+ buffer =( ((u16*) buffer) + 256 ); -+ } -+ } -+ -+ sector += sectodo; -+ sectorcnt -= sectodo; -+ } -+ -+ return sectorcnt_original ; -+ } -+ -+ /**************/ -+ static int do_writerequest( -+ struct mpc52xx_blockata_priv *priv, -+ struct request *req, -+ struct bio *bio, -+ int bio_index, -+ sector_t sector, -+ int sectorcnt, -+ u16 *buffer) -+ { -+ int ret; -+ int secperreq; -+ int sectodo; -+ int sectorcnt_original = sectorcnt; -+ -+ NPRINTK("%s: sector=%ld, sectorcnt=%d, buffer=%p\n", __func__, (long) sector, sectorcnt, buffer); -+ -+ secperreq = priv->multi_secpercmd; -+ -+ while(sectorcnt) -+ { -+ int i; -+ sectodo = sectorcnt > secperreq ? secperreq : sectorcnt; -+ -+ ret = wait_not_busy(priv); -+ if (ret!=0) -+ return ret; -+ mpc52xx_ata_setupsector(priv, sector, sectodo, 1); -+ -+ ret = wait_ready(priv); -+ if (ret!=0) { -+ NPRINTK("can't wait rdy=%d. 0x%x\n", ret, read_altstatus(priv)); -+ ATA_DUMPREG -+ return ret; -+ } -+ -+ if (priv->multi_available) { -+ /* If the drive support the multi write, let's go! -+ * should be really faster as we don't have to wait for DRQ -+ * However, either I make something wrong, either I did not find -+ * any disk supporting this! -+ */ -+ write_cmd(priv, ATA_CMD_WRITE_MULTI); -+ ret = wait_drq(priv); -+ if (ret!=0) { -+ NPRINTK("can't wait drq %d\n", ret); -+ ATA_DUMPREG -+ return ret; -+ } -+ -+ ret = ata_dopollwrite(priv, buffer, 256*sectodo); -+ buffer = ( (u16*) buffer + 256*sectodo ); -+ } else { -+ write_cmd(priv, ATA_CMD_PIO_WRITE); -+ for(i=0; i < sectodo; i++) { -+ ret = wait_drq(priv); -+ if (ret!=0) { -+ ATA_DUMPREG -+ return ret; -+ } -+ -+ ret = ata_dopollwrite(priv, buffer, 256 ); -+ -+ // Check! -+ -+ buffer = ( ((u16*) buffer) + 256 ); -+ } -+ } -+ -+ sector += sectodo; -+ sectorcnt-= sectodo; -+ } -+ -+ //NPRINTK("return %d\n", sectorcnt_original); -+ return sectorcnt_original; -+ } -+#endif /* CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA */ -+ -+ /**************/ -+ /**************/ -+ /**************/ -+ /* -+ * This is call by nicoskel -+ */ -+ -+ int mpc52xx_ata_dotransfer( -+ struct mpc52xx_blockata_priv *priv, -+ struct request *req, -+ struct bio *bio, -+ int bio_index, -+ sector_t sector, -+ int sectorcnt, -+ char *buffer, -+ int is_write) -+ { -+#ifdef CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA -+#warning Using interrupt based SDMA -+ int ret; -+ -+ if (is_write) -+ { -+ /* -+ * for TX beter wait the drive interrupt -+ * because we first write into drive buffer and the drive do the real stuff -+ */ -+ sdma_ata_tx_init(priv->sdma); -+ -+ ret = start_writerequest(priv, req, bio, bio_index, sector, sectorcnt, (u16 *) buffer); -+ } else -+ { -+ /* -+ * for RX better write for sdma int -+ * because the drive will first to the read and then the SDMA task fetch -+ * the data from the FIFO -+ */ -+ sdma_ata_rx_init(priv->sdma); -+ -+ // Wait for int before starting the task -+ ret = start_readrequest(priv, req, bio, bio_index, sector, sectorcnt, (u16 *) buffer); -+ } -+ -+ return ret; -+ -+#else /* CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA */ -+#warning Using poll based SDMA -> Slow and obsolet! -+ return -+ is_write -+ ? do_writerequest(priv, req, bio, bio_index, sector, sectorcnt, (u16 *) buffer) -+ : do_readrequest(priv, req, bio, bio_index, sector, sectorcnt, (u16 *) buffer); -+#endif /* CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA */ -+ } -+ -+ -+ -+ /**************/ -+ /**************/ -+ int mpc52xx_ata_docpupollread( -+ struct mpc52xx_blockata_priv *priv, -+ void *buffer, -+ int len) -+ { -+ u16 *buffer16 = (u16 *) buffer; -+ int local_len = len; -+ -+ while(local_len--) -+ *buffer16++ = read_data(priv); -+ -+ return len - local_len; -+ } -+ -+#ifdef CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA -+#if 0 -+ static int ata_dosdmapollwrite( -+ struct mpc52xx_blockata_priv *priv, -+ void *buffer, -+ int len) -+ { -+ int ret = 0; -+ u32 port_BusAddr; -+ u32 addr_BusAddr; -+ int taskirq; -+ int timeout = 10*1000; -+ -+ //NPRINTK("%s: have to read %d , from port 0x%8.8lx to mem %p\n", __func__, count, port, addr); -+ -+ taskirq = priv->sdma_irq; -+ port_BusAddr = ATAFIFO_BUSADDR; -+ -+ addr_BusAddr = virt_to_phys( (void*) buffer); -+ -+ //NPRINTK("%s:priv=%p, irq=%d, port bus=0x%8.8x, addr bus =0x%8.8x\n", -+ // __func__, priv, taskirq, port_BusAddr, addr_BusAddr) -+ -+ // Turn the SDMA into RX -+ sdma_ata_tx_init(priv->sdma); -+ -+ sdma_ata_submit_buffer(priv->sdma, (void *)buffer, (void *) addr_BusAddr, (void *)port_BusAddr, len*2); -+ -+ sdma_ata_clear_irq(priv->sdma); -+ sdma_ata_enable(priv->sdma); -+ -+ for(;;) -+ { -+ -+ u32 val; -+ val = in_be32(&sdma.io->IntPend); -+ if ( (val & (1 << priv->sdma->tasknum) ) ) -+ break; -+ -+ if (timeout--<=0) { -+ ret = -1; -+ printk("timeout 0x%x\n", read_altstatus(priv) ); -+ break; -+ } -+ -+ udelay(1); -+ } -+ -+ sdma_ata_disable(priv->sdma); -+ sdma_ata_reset(priv->sdma); -+ -+ return 0; -+ } -+ -+ static int ata_dosdmapollread( -+ struct mpc52xx_blockata_priv *priv, -+ void *buffer, -+ int len) -+ { -+ int ret = 0; -+ u32 port_BusAddr; -+ u32 addr_BusAddr; -+ int taskirq; -+ int timeout = 10*1000; -+ -+ taskirq = priv->sdma_irq; -+ port_BusAddr = ATAFIFO_BUSADDR; -+ addr_BusAddr = virt_to_phys( (void*) buffer); -+ -+ // Turn the SDMA into RX -+ sdma_ata_rx_init(priv->sdma); -+ -+ sdma_ata_submit_buffer(priv->sdma, (void *)buffer, (void *)port_BusAddr, (void *) addr_BusAddr, len*2); -+ -+ sdma_ata_clear_irq(priv->sdma); -+ sdma_ata_enable(priv->sdma); -+ -+ for(;;) -+ { -+ u32 val; -+ val = in_be32(&sdma.io->IntPend); -+ if ( (val & (1 << priv->sdma->tasknum) ) ) -+ break; -+ -+ if (timeout--<=0) { -+ printk("timeout 0x%x\n", read_altstatus(priv) ); -+ ret = -1; -+ break; -+ } -+ -+ udelay(1); -+ } -+ -+ sdma_ata_disable(priv->sdma); -+ sdma_ata_reset(priv->sdma); -+ -+ return ret; -+ } -+#endif -+#endif -+ -+ /**************/ -+ int mpc52xx_ata_docpupollwrite( -+ struct mpc52xx_blockata_priv *priv, -+ void *buffer, -+ int len) -+ { -+ u16 *buffer16 = (u16 *) buffer; -+ int local_len = len; -+ -+ while(local_len--) -+ write_data(priv, *buffer16++); -+ -+ return len - local_len; -+ } -+ -+/* -+ * -+*/ -+ -+EXPORT_SYMBOL(mpc52xx_ata_docpupollread); -+EXPORT_SYMBOL(mpc52xx_ata_docpupollwrite); -+EXPORT_SYMBOL(mpc52xx_ata_dotransfer); -+EXPORT_SYMBOL(sdma_void_handler); -+EXPORT_SYMBOL(ata_void_handler); -+EXPORT_SYMBOL(mpc52xx_ata_ack_blkreq); --- -1.4.3.2 - diff --git a/debian/patches/features/powerpc/efika/0008-ohci-Rework-bus-glue-integration-to-allow-several-at-once.txt b/debian/patches/features/powerpc/efika/0008-ohci-Rework-bus-glue-integration-to-allow-several-at-once.txt new file mode 100644 index 000000000..c209ee035 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0008-ohci-Rework-bus-glue-integration-to-allow-several-at-once.txt @@ -0,0 +1,470 @@ +From 51294aa1482ea961a3e51ddac587b70b7c1c8ba0 Mon Sep 17 00:00:00 2001 +From: Sylvain Munaut +Date: Wed, 13 Dec 2006 20:35:37 +0100 +Subject: [PATCH] [PATCH] ohci: Rework bus glue integration to allow several at once + +The previous model had the module_init & module_exit function in the +bus glue .c files themselves. That's a problem if several glues need +to be selected at once and the driver is built has module. This case +is quite common in embedded system where you want to handle both the +integrated ohci controller and some extra controller on PCI. + +The ohci-hcd.c file now provide the module_init & module_exit and +appropriate driver registering/unregistering is done conditionally, +using #ifdefs. + +Signed-off-by: Sylvain Munaut +Acked-by: David Brownell +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/host/ohci-at91.c | 15 ------ + drivers/usb/host/ohci-au1xxx.c | 16 ------ + drivers/usb/host/ohci-ep93xx.c | 12 ----- + drivers/usb/host/ohci-hcd.c | 98 +++++++++++++++++++++++++++++++++------ + drivers/usb/host/ohci-lh7a404.c | 16 ------ + drivers/usb/host/ohci-omap.c | 19 -------- + drivers/usb/host/ohci-pci.c | 20 -------- + drivers/usb/host/ohci-pnx4008.c | 12 ----- + drivers/usb/host/ohci-pnx8550.c | 16 ------ + drivers/usb/host/ohci-ppc-soc.c | 16 ------ + drivers/usb/host/ohci-pxa27x.c | 16 ------ + drivers/usb/host/ohci-s3c2410.c | 12 ----- + drivers/usb/host/ohci-sa1111.c | 16 ------ + 13 files changed, 83 insertions(+), 201 deletions(-) + +diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c +index cc40551..53f62cf 100644 +--- a/drivers/usb/host/ohci-at91.c ++++ b/drivers/usb/host/ohci-at91.c +@@ -320,18 +320,3 @@ static struct platform_driver ohci_hcd_at91_driver = { + }, + }; + +-static int __init ohci_hcd_at91_init (void) +-{ +- if (usb_disabled()) +- return -ENODEV; +- +- return platform_driver_register(&ohci_hcd_at91_driver); +-} +- +-static void __exit ohci_hcd_at91_cleanup (void) +-{ +- platform_driver_unregister(&ohci_hcd_at91_driver); +-} +- +-module_init (ohci_hcd_at91_init); +-module_exit (ohci_hcd_at91_cleanup); +diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c +index e70b243..663a060 100644 +--- a/drivers/usb/host/ohci-au1xxx.c ++++ b/drivers/usb/host/ohci-au1xxx.c +@@ -345,19 +345,3 @@ static struct platform_driver ohci_hcd_au1xxx_driver = { + }, + }; + +-static int __init ohci_hcd_au1xxx_init (void) +-{ +- pr_debug (DRIVER_INFO " (Au1xxx)"); +- pr_debug ("block sizes: ed %d td %d\n", +- sizeof (struct ed), sizeof (struct td)); +- +- return platform_driver_register(&ohci_hcd_au1xxx_driver); +-} +- +-static void __exit ohci_hcd_au1xxx_cleanup (void) +-{ +- platform_driver_unregister(&ohci_hcd_au1xxx_driver); +-} +- +-module_init (ohci_hcd_au1xxx_init); +-module_exit (ohci_hcd_au1xxx_cleanup); +diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c +index 43ae696..e9974c3 100644 +--- a/drivers/usb/host/ohci-ep93xx.c ++++ b/drivers/usb/host/ohci-ep93xx.c +@@ -214,15 +214,3 @@ static struct platform_driver ohci_hcd_ep93xx_driver = { + }, + }; + +-static int __init ohci_hcd_ep93xx_init(void) +-{ +- return platform_driver_register(&ohci_hcd_ep93xx_driver); +-} +- +-static void __exit ohci_hcd_ep93xx_cleanup(void) +-{ +- platform_driver_unregister(&ohci_hcd_ep93xx_driver); +-} +- +-module_init(ohci_hcd_ep93xx_init); +-module_exit(ohci_hcd_ep93xx_cleanup); +diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c +index c1c1d87..9926b8f 100644 +--- a/drivers/usb/host/ohci-hcd.c ++++ b/drivers/usb/host/ohci-hcd.c +@@ -855,63 +855,131 @@ MODULE_LICENSE ("GPL"); + + #ifdef CONFIG_PCI + #include "ohci-pci.c" ++#define PCI_DRIVER ohci_pci_driver + #endif + + #ifdef CONFIG_SA1111 + #include "ohci-sa1111.c" ++#define SA1111_DRIVER ohci_hcd_sa1111_driver + #endif + + #ifdef CONFIG_ARCH_S3C2410 + #include "ohci-s3c2410.c" ++#define PLATFORM_DRIVER ohci_hcd_s3c2410_driver + #endif + + #ifdef CONFIG_ARCH_OMAP + #include "ohci-omap.c" ++#define PLATFORM_DRIVER ohci_hcd_omap_driver + #endif + + #ifdef CONFIG_ARCH_LH7A404 + #include "ohci-lh7a404.c" ++#define PLATFORM_DRIVER ohci_hcd_lh7a404_driver + #endif + + #ifdef CONFIG_PXA27x + #include "ohci-pxa27x.c" ++#define PLATFORM_DRIVER ohci_hcd_pxa27x_driver + #endif + + #ifdef CONFIG_ARCH_EP93XX + #include "ohci-ep93xx.c" ++#define PLATFORM_DRIVER ohci_hcd_ep93xx_driver + #endif + + #ifdef CONFIG_SOC_AU1X00 + #include "ohci-au1xxx.c" ++#define PLATFORM_DRIVER ohci_hcd_au1xxx_driver + #endif + +-#ifdef CONFIG_PNX8550 +-#include "ohci-pnx8550.c" +-#endif ++#ifdef CONFIG_PNX8550 ++#include "ohci-pnx8550.c" ++#define PLATFORM_DRIVER ohci_hcd_pnx8550_driver ++#endif + + #ifdef CONFIG_USB_OHCI_HCD_PPC_SOC + #include "ohci-ppc-soc.c" ++#define PLATFORM_DRIVER ohci_hcd_ppc_soc_driver + #endif + + #ifdef CONFIG_ARCH_AT91 + #include "ohci-at91.c" ++#define PLATFORM_DRIVER ohci_hcd_at91_driver + #endif + + #ifdef CONFIG_ARCH_PNX4008 + #include "ohci-pnx4008.c" ++#define PLATFORM_DRIVER usb_hcd_pnx4008_driver + #endif + +-#if !(defined(CONFIG_PCI) \ +- || defined(CONFIG_SA1111) \ +- || defined(CONFIG_ARCH_S3C2410) \ +- || defined(CONFIG_ARCH_OMAP) \ +- || defined (CONFIG_ARCH_LH7A404) \ +- || defined (CONFIG_PXA27x) \ +- || defined (CONFIG_ARCH_EP93XX) \ +- || defined (CONFIG_SOC_AU1X00) \ +- || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \ +- || defined (CONFIG_ARCH_AT91) \ +- || defined (CONFIG_ARCH_PNX4008) \ +- ) ++ ++#if !defined(PCI_DRIVER) && \ ++ !defined(PLATFORM_DRIVER) && \ ++ !defined(SA1111_DRIVER) + #error "missing bus glue for ohci-hcd" + #endif ++ ++static int __init ohci_hcd_mod_init(void) ++{ ++ int retval = 0; ++ int ls = 0; ++ ++ if (usb_disabled()) ++ return -ENODEV; ++ ++ printk (KERN_DEBUG "%s: " DRIVER_INFO "\n", hcd_name); ++ pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name, ++ sizeof (struct ed), sizeof (struct td)); ++ ++#ifdef PLATFORM_DRIVER ++ retval = platform_driver_register(&PLATFORM_DRIVER); ++ if (retval < 0) ++ return retval; ++ ls++; ++#endif ++ ++#ifdef SA1111_DRIVER ++ retval = sa1111_driver_register(&SA1111_DRIVER); ++ if (retval < 0) ++ goto error; ++ ls++; ++#endif ++ ++#ifdef PCI_DRIVER ++ retval = pci_register_driver(&PCI_DRIVER); ++ if (retval < 0) ++ goto error; ++ ls++; ++#endif ++ ++ return retval; ++ ++ /* Error path */ ++error: ++#ifdef PLATFORM_DRIVER ++ if (ls--) ++ platform_driver_unregister(&PLATFORM_DRIVER); ++#endif ++#ifdef SA1111_DRIVER ++ if (ls--) ++ sa1111_driver_unregister(&SA1111_DRIVER); ++#endif ++ return retval; ++} ++module_init(ohci_hcd_mod_init); ++ ++static void __exit ohci_hcd_mod_exit(void) ++{ ++#ifdef PCI_DRIVER ++ pci_unregister_driver(&PCI_DRIVER); ++#endif ++#ifdef SA1111_DRIVER ++ sa1111_driver_unregister(&SA1111_DRIVER); ++#endif ++#ifdef PLATFORM_DRIVER ++ platform_driver_unregister(&PLATFORM_DRIVER); ++#endif ++} ++module_exit(ohci_hcd_mod_exit); ++ +diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c +index e9807cf..4a043ab 100644 +--- a/drivers/usb/host/ohci-lh7a404.c ++++ b/drivers/usb/host/ohci-lh7a404.c +@@ -251,19 +251,3 @@ static struct platform_driver ohci_hcd_lh7a404_driver = { + }, + }; + +-static int __init ohci_hcd_lh7a404_init (void) +-{ +- pr_debug (DRIVER_INFO " (LH7A404)"); +- pr_debug ("block sizes: ed %d td %d\n", +- sizeof (struct ed), sizeof (struct td)); +- +- return platform_driver_register(&ohci_hcd_lh7a404_driver); +-} +- +-static void __exit ohci_hcd_lh7a404_cleanup (void) +-{ +- platform_driver_unregister(&ohci_hcd_lh7a404_driver); +-} +- +-module_init (ohci_hcd_lh7a404_init); +-module_exit (ohci_hcd_lh7a404_cleanup); +diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c +index 27be1f9..5cfa3d1 100644 +--- a/drivers/usb/host/ohci-omap.c ++++ b/drivers/usb/host/ohci-omap.c +@@ -544,22 +544,3 @@ static struct platform_driver ohci_hcd_omap_driver = { + }, + }; + +-static int __init ohci_hcd_omap_init (void) +-{ +- printk (KERN_DEBUG "%s: " DRIVER_INFO " (OMAP)\n", hcd_name); +- if (usb_disabled()) +- return -ENODEV; +- +- pr_debug("%s: block sizes: ed %Zd td %Zd\n", hcd_name, +- sizeof (struct ed), sizeof (struct td)); +- +- return platform_driver_register(&ohci_hcd_omap_driver); +-} +- +-static void __exit ohci_hcd_omap_cleanup (void) +-{ +- platform_driver_unregister(&ohci_hcd_omap_driver); +-} +- +-module_init (ohci_hcd_omap_init); +-module_exit (ohci_hcd_omap_cleanup); +diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c +index 292daf0..b331ac4 100644 +--- a/drivers/usb/host/ohci-pci.c ++++ b/drivers/usb/host/ohci-pci.c +@@ -311,23 +311,3 @@ static struct pci_driver ohci_pci_driver = { + .shutdown = usb_hcd_pci_shutdown, + }; + +- +-static int __init ohci_hcd_pci_init (void) +-{ +- printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name); +- if (usb_disabled()) +- return -ENODEV; +- +- pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name, +- sizeof (struct ed), sizeof (struct td)); +- return pci_register_driver (&ohci_pci_driver); +-} +-module_init (ohci_hcd_pci_init); +- +-/*-------------------------------------------------------------------------*/ +- +-static void __exit ohci_hcd_pci_cleanup (void) +-{ +- pci_unregister_driver (&ohci_pci_driver); +-} +-module_exit (ohci_hcd_pci_cleanup); +diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c +index 3a8cbfb..893b172 100644 +--- a/drivers/usb/host/ohci-pnx4008.c ++++ b/drivers/usb/host/ohci-pnx4008.c +@@ -465,15 +465,3 @@ static struct platform_driver usb_hcd_pnx4008_driver = { + .remove = usb_hcd_pnx4008_remove, + }; + +-static int __init usb_hcd_pnx4008_init(void) +-{ +- return platform_driver_register(&usb_hcd_pnx4008_driver); +-} +- +-static void __exit usb_hcd_pnx4008_cleanup(void) +-{ +- return platform_driver_unregister(&usb_hcd_pnx4008_driver); +-} +- +-module_init(usb_hcd_pnx4008_init); +-module_exit(usb_hcd_pnx4008_cleanup); +diff --git a/drivers/usb/host/ohci-pnx8550.c b/drivers/usb/host/ohci-pnx8550.c +index 6922b91..de45eb0 100644 +--- a/drivers/usb/host/ohci-pnx8550.c ++++ b/drivers/usb/host/ohci-pnx8550.c +@@ -240,19 +240,3 @@ static struct platform_driver ohci_hcd_pnx8550_driver = { + .remove = ohci_hcd_pnx8550_drv_remove, + }; + +-static int __init ohci_hcd_pnx8550_init (void) +-{ +- pr_debug (DRIVER_INFO " (pnx8550)"); +- pr_debug ("block sizes: ed %d td %d\n", +- sizeof (struct ed), sizeof (struct td)); +- +- return platform_driver_register(&ohci_hcd_pnx8550_driver); +-} +- +-static void __exit ohci_hcd_pnx8550_cleanup (void) +-{ +- platform_driver_unregister(&ohci_hcd_pnx8550_driver); +-} +- +-module_init (ohci_hcd_pnx8550_init); +-module_exit (ohci_hcd_pnx8550_cleanup); +diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c +index c7ce8e6..1a2e177 100644 +--- a/drivers/usb/host/ohci-ppc-soc.c ++++ b/drivers/usb/host/ohci-ppc-soc.c +@@ -208,19 +208,3 @@ static struct platform_driver ohci_hcd_ppc_soc_driver = { + }, + }; + +-static int __init ohci_hcd_ppc_soc_init(void) +-{ +- pr_debug(DRIVER_INFO " (PPC SOC)\n"); +- pr_debug("block sizes: ed %d td %d\n", sizeof(struct ed), +- sizeof(struct td)); +- +- return platform_driver_register(&ohci_hcd_ppc_soc_driver); +-} +- +-static void __exit ohci_hcd_ppc_soc_cleanup(void) +-{ +- platform_driver_unregister(&ohci_hcd_ppc_soc_driver); +-} +- +-module_init(ohci_hcd_ppc_soc_init); +-module_exit(ohci_hcd_ppc_soc_cleanup); +diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c +index 3bbea84..f1563dc 100644 +--- a/drivers/usb/host/ohci-pxa27x.c ++++ b/drivers/usb/host/ohci-pxa27x.c +@@ -369,19 +369,3 @@ static struct platform_driver ohci_hcd_pxa27x_driver = { + }, + }; + +-static int __init ohci_hcd_pxa27x_init (void) +-{ +- pr_debug (DRIVER_INFO " (pxa27x)"); +- pr_debug ("block sizes: ed %d td %d\n", +- sizeof (struct ed), sizeof (struct td)); +- +- return platform_driver_register(&ohci_hcd_pxa27x_driver); +-} +- +-static void __exit ohci_hcd_pxa27x_cleanup (void) +-{ +- platform_driver_unregister(&ohci_hcd_pxa27x_driver); +-} +- +-module_init (ohci_hcd_pxa27x_init); +-module_exit (ohci_hcd_pxa27x_cleanup); +diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c +index b350d45..6829814 100644 +--- a/drivers/usb/host/ohci-s3c2410.c ++++ b/drivers/usb/host/ohci-s3c2410.c +@@ -501,15 +501,3 @@ static struct platform_driver ohci_hcd_s3c2410_driver = { + }, + }; + +-static int __init ohci_hcd_s3c2410_init (void) +-{ +- return platform_driver_register(&ohci_hcd_s3c2410_driver); +-} +- +-static void __exit ohci_hcd_s3c2410_cleanup (void) +-{ +- platform_driver_unregister(&ohci_hcd_s3c2410_driver); +-} +- +-module_init (ohci_hcd_s3c2410_init); +-module_exit (ohci_hcd_s3c2410_cleanup); +diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c +index fe0090e..0f48f2d 100644 +--- a/drivers/usb/host/ohci-sa1111.c ++++ b/drivers/usb/host/ohci-sa1111.c +@@ -269,19 +269,3 @@ static struct sa1111_driver ohci_hcd_sa1111_driver = { + .remove = ohci_hcd_sa1111_drv_remove, + }; + +-static int __init ohci_hcd_sa1111_init (void) +-{ +- dbg (DRIVER_INFO " (SA-1111)"); +- dbg ("block sizes: ed %d td %d", +- sizeof (struct ed), sizeof (struct td)); +- +- return sa1111_driver_register(&ohci_hcd_sa1111_driver); +-} +- +-static void __exit ohci_hcd_sa1111_cleanup (void) +-{ +- sa1111_driver_unregister(&ohci_hcd_sa1111_driver); +-} +- +-module_init (ohci_hcd_sa1111_init); +-module_exit (ohci_hcd_sa1111_cleanup); +-- +1.4.4.2 + diff --git a/debian/patches/features/powerpc/efika/0002-Add-USB-OHCI-glue-for-OpenFirmware-devices.diff b/debian/patches/features/powerpc/efika/0009-ohci-Add-support-for-OHCI-controller-on-the-of_platform-bus.txt similarity index 50% rename from debian/patches/features/powerpc/efika/0002-Add-USB-OHCI-glue-for-OpenFirmware-devices.diff rename to debian/patches/features/powerpc/efika/0009-ohci-Add-support-for-OHCI-controller-on-the-of_platform-bus.txt index 86dd8f3e3..2b53e487f 100644 --- a/debian/patches/features/powerpc/efika/0002-Add-USB-OHCI-glue-for-OpenFirmware-devices.diff +++ b/debian/patches/features/powerpc/efika/0009-ohci-Add-support-for-OHCI-controller-on-the-of_platform-bus.txt @@ -1,35 +1,43 @@ -From bc515daf6d0845b0ddb739f3ba822b66f84344a7 Mon Sep 17 00:00:00 2001 -From: Nicolas DET -Date: Fri, 24 Nov 2006 12:55:37 +0100 -Subject: [PATCH] Add USB/OHCI glue for OpenFirmware devices +From 944afcaa19737396ed514e3e845a3db2de9377f3 Mon Sep 17 00:00:00 2001 +From: Sylvain Munaut +Date: Wed, 13 Dec 2006 21:03:30 +0100 +Subject: [PATCH] [PATCH] ohci: Add support for OHCI controller on the of_platform bus -Signed-off-by: Nicolas DET +PPC embedded systems can have a ohci controller builtin. In the +new model, it will end up as a driver on the of_platform bus, +this patches takes care of them. + +Signed-off-by: Sylvain Munaut +Acked-by: David Brownell +Signed-off-by: Greg Kroah-Hartman --- - drivers/usb/host/Kconfig | 19 +++ - drivers/usb/host/ohci-hcd.c | 6 + - drivers/usb/host/ohci-ppc-of.c | 285 ++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 310 insertions(+), 0 deletions(-) + drivers/usb/host/Kconfig | 23 ++++- + drivers/usb/host/ohci-hcd.c | 20 ++++ + drivers/usb/host/ohci-ppc-of.c | 232 ++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 274 insertions(+), 1 deletions(-) diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig -index cf10cbc..f5ef6f5 100644 +index faabce8..c49715d 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig -@@ -106,6 +106,25 @@ config USB_OHCI_HCD_PPC_SOC +@@ -107,9 +107,30 @@ config USB_OHCI_HCD_PPC_SOC Enables support for the USB controller on the MPC52xx or STB03xxx processor chip. If unsure, say Y. +config USB_OHCI_HCD_PPC_OF -+ bool "OHCI support for PPC USB controller for OpenFirmware platform" ++ bool "OHCI support for PPC USB controller on OF platform bus" + depends on USB_OHCI_HCD && PPC_OF + default y + ---help--- -+ Enables support for the USB controller PowerPC OpenFirmware platform ++ Enables support for the USB controller PowerPC present on the ++ OpenFirmware platform bus. + +config USB_OHCI_HCD_PPC_OF_BE + bool "Support big endian HC" + depends on USB_OHCI_HCD_PPC_OF + default y -+ select USB_OHCI_BIG_ENDIAN ++ select USB_OHCI_BIG_ENDIAN_DESC ++ select USB_OHCI_BIG_ENDIAN_MMIO + +config USB_OHCI_HCD_PPC_OF_LE + bool "Support little endian HC" @@ -39,156 +47,91 @@ index cf10cbc..f5ef6f5 100644 + config USB_OHCI_HCD_PCI bool "OHCI support for PCI-bus USB controllers" - depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx) +- depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx) ++ depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx || USB_OHCI_HCD_PPC_OF) + default y + select USB_OHCI_LITTLE_ENDIAN + ---help--- diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c -index 9be6b30..04413b6 100644 +index 9926b8f..c6ae1ff 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c -@@ -930,6 +930,10 @@ #ifdef CONFIG_USB_OHCI_HCD_PPC_SOC - #include "ohci-ppc-soc.c" +@@ -914,8 +914,14 @@ MODULE_LICENSE ("GPL"); #endif + +#ifdef CONFIG_USB_OHCI_HCD_PPC_OF +#include "ohci-ppc-of.c" ++#define OF_PLATFORM_DRIVER ohci_hcd_ppc_of_driver +#endif + - #if defined(CONFIG_ARCH_AT91RM9200) || defined(CONFIG_ARCH_AT91SAM9261) - #include "ohci-at91.c" - #endif -@@ -950,6 +954,8 @@ #if !(defined(CONFIG_PCI) \ - || defined (CONFIG_ARCH_AT91RM9200) \ - || defined (CONFIG_ARCH_AT91SAM9261) \ - || defined (CONFIG_ARCH_PNX4008) \ -+ || defined (CONFIG_USB_OHCI_HCD_PPC_OF_LE) \ -+ || defined (CONFIG_USB_OHCI_HCD_PPC_OF_BE) \ - ) + #if !defined(PCI_DRIVER) && \ + !defined(PLATFORM_DRIVER) && \ ++ !defined(OF_PLATFORM_DRIVER) && \ + !defined(SA1111_DRIVER) #error "missing bus glue for ohci-hcd" #endif +@@ -939,6 +945,13 @@ static int __init ohci_hcd_mod_init(void) + ls++; + #endif + ++#ifdef OF_PLATFORM_DRIVER ++ retval = of_register_platform_driver(&OF_PLATFORM_DRIVER); ++ if (retval < 0) ++ goto error; ++ ls++; ++#endif ++ + #ifdef SA1111_DRIVER + retval = sa1111_driver_register(&SA1111_DRIVER); + if (retval < 0) +@@ -961,6 +974,10 @@ error: + if (ls--) + platform_driver_unregister(&PLATFORM_DRIVER); + #endif ++#ifdef OF_PLATFORM_DRIVER ++ if (ls--) ++ of_unregister_platform_driver(&OF_PLATFORM_DRIVER); ++#endif + #ifdef SA1111_DRIVER + if (ls--) + sa1111_driver_unregister(&SA1111_DRIVER); +@@ -977,6 +994,9 @@ static void __exit ohci_hcd_mod_exit(void) + #ifdef SA1111_DRIVER + sa1111_driver_unregister(&SA1111_DRIVER); + #endif ++#ifdef OF_PLATFORM_DRIVER ++ of_unregister_platform_driver(&OF_PLATFORM_DRIVER); ++#endif + #ifdef PLATFORM_DRIVER + platform_driver_unregister(&PLATFORM_DRIVER); + #endif diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c new file mode 100644 -index 0000000..30ce520 +index 0000000..84b555b --- /dev/null +++ b/drivers/usb/host/ohci-ppc-of.c -@@ -0,0 +1,285 @@ +@@ -0,0 +1,232 @@ +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 2000-2002 David Brownell + * (C) Copyright 2002 Hewlett-Packard Company -+ * (C) Copyright 2003-2005 MontaVista Software Inc. ++ * (C) Copyright 2006 Sylvain Munaut + * -+ * Probe and init OHCI Big endian HC from OpenFirmware device tree -+ * Tested on Efika 5k2 ++ * Bus glue for OHCI HC on the of_platform bus + * -+ * Modified by Dale Farnsworth from ohci-sa1111.c ++ * Modified for of_platform bus from ohci-sa1111.c + * + * This file is licenced under the GPL. + */ + +#include + -+#include +#include +#include + -+/* configure so an HC device and id are always provided */ -+/* always called with process context; sleeping is OK */ -+ -+/* -+ * usb_hcd_ppc_of_probe - initialize On-Chip HCDs -+ * Context: !in_interrupt() -+ * -+ * Allocates basic resources for this USB host controller. -+ * -+ * Store this function in the HCD's struct pci_driver as probe(). -+ */ -+static int usb_hcd_ppc_of_probe(const struct hc_driver *driver, -+ struct of_device *dev, int is_bigendian) -+{ -+ int retval; -+ struct usb_hcd *hcd; -+ struct ohci_hcd *ohci; -+ struct resource res; -+ int irq; -+ int ret; -+ -+ pr_debug("initializing PPC-OF USB Controller\n"); -+ -+ if ((ret = of_address_to_resource(dev->node, 0, &res)) != 0) -+ return ret; -+ -+ hcd = usb_create_hcd(driver, &dev->dev, "PPC-OF USB"); -+ if (!hcd) -+ return -ENOMEM; -+ -+ hcd->rsrc_start = res.start; -+ hcd->rsrc_len = res.end - res.start + 1; -+ -+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { -+ pr_debug(__FILE__ ": request_mem_region failed\n"); -+ retval = -EBUSY; -+ goto err1; -+ } -+ -+ irq = irq_of_parse_and_map(dev->node, 0); -+ if (irq == NO_IRQ) { -+ retval = -EBUSY; -+ goto err2; -+ } -+ -+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); -+ if (!hcd->regs) { -+ pr_debug(__FILE__ ": ioremap failed\n"); -+ retval = -ENOMEM; -+ goto err2; -+ } -+ -+ ohci = hcd_to_ohci(hcd); -+ if (is_bigendian) -+ ohci->flags |= OHCI_BIG_ENDIAN; -+ -+ ohci_hcd_init(ohci); -+ -+ retval = usb_add_hcd(hcd, irq, 0); -+ if (retval == 0) -+ return retval; -+ -+ pr_debug("Removing PPC-OF USB Controller\n"); -+ -+ iounmap(hcd->regs); -+ err2: -+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -+ err1: -+ usb_put_hcd(hcd); -+ return retval; -+} -+ -+ -+/* may be called without controller electrically present */ -+/* may be called with controller, bus, and devices active */ -+ -+/* -+ * usb_hcd_ppc_of_remove - shutdown processing for On-Chip HCDs -+ * @pdev: USB Host Controller being removed -+ * Context: !in_interrupt() -+ * -+ * Reverses the effect of usb_hcd_ppc_of_probe(). -+ * It is always called from a thread -+ * context, normally "rmmod", "apmd", or something similar. -+ * -+ */ -+static void usb_hcd_ppc_of_remove(struct usb_hcd *hcd, -+ struct of_device *op) -+{ -+ usb_remove_hcd(hcd); -+ -+ pr_debug("stopping PPC-OF USB Controller\n"); -+ -+ iounmap(hcd->regs); -+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -+ usb_put_hcd(hcd); -+} + +static int __devinit +ohci_ppc_of_start(struct usb_hcd *hcd) @@ -210,6 +153,7 @@ index 0000000..30ce520 + +static const struct hc_driver ohci_ppc_of_hc_driver = { + .description = hcd_name, ++ .product_desc = "OF OHCI", + .hcd_priv_size = sizeof(struct ohci_hcd), + + /* @@ -251,17 +195,98 @@ index 0000000..30ce520 +}; + + ++static int __devinit ++ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match) ++{ ++ struct device_node *dn = op->node; ++ struct usb_hcd *hcd; ++ struct ohci_hcd *ohci; ++ struct resource res; ++ int irq; + -+static int ohci_hcd_ppc_of_drv_remove(struct of_device *op) ++ int rv; ++ int is_bigendian; ++ ++ if (usb_disabled()) ++ return -ENODEV; ++ ++ is_bigendian = ++ device_is_compatible(dn, "ohci-bigendian") || ++ device_is_compatible(dn, "ohci-be");; ++ ++ dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n"); ++ ++ rv = of_address_to_resource(dn, 0, &res); ++ if (rv) ++ return rv; ++ ++ hcd = usb_create_hcd(&ohci_ppc_of_hc_driver, &op->dev, "PPC-OF USB"); ++ if (!hcd) ++ return -ENOMEM; ++ ++ hcd->rsrc_start = res.start; ++ hcd->rsrc_len = res.end - res.start + 1; ++ ++ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { ++ printk(KERN_ERR __FILE__ ": request_mem_region failed\n"); ++ rv = -EBUSY; ++ goto err_rmr; ++ } ++ ++ irq = irq_of_parse_and_map(dn, 0); ++ if (irq == NO_IRQ) { ++ printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n"); ++ rv = -EBUSY; ++ goto err_irq; ++ } ++ ++ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); ++ if (!hcd->regs) { ++ printk(KERN_ERR __FILE__ ": ioremap failed\n"); ++ rv = -ENOMEM; ++ goto err_ioremap; ++ } ++ ++ ohci = hcd_to_ohci(hcd); ++ if (is_bigendian) ++ ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; ++ ++ ohci_hcd_init(ohci); ++ ++ rv = usb_add_hcd(hcd, irq, 0); ++ if (rv == 0) ++ return 0; ++ ++ iounmap(hcd->regs); ++err_ioremap: ++ irq_dispose_mapping(irq); ++err_irq: ++ release_mem_region(hcd->rsrc_start, hcd->rsrc_len); ++err_rmr: ++ usb_put_hcd(hcd); ++ ++ return rv; ++} ++ ++static int ohci_hcd_ppc_of_remove(struct of_device *op) +{ + struct usb_hcd *hcd = dev_get_drvdata(&op->dev); + dev_set_drvdata(&op->dev, NULL); + -+ usb_hcd_ppc_of_remove(hcd, op); ++ dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n"); ++ ++ usb_remove_hcd(hcd); ++ ++ iounmap(hcd->regs); ++ irq_dispose_mapping(hcd->irq); ++ release_mem_region(hcd->rsrc_start, hcd->rsrc_len); ++ ++ usb_put_hcd(hcd); ++ + return 0; +} + -+static int ohci_hcd_ppc_of_drv_shutdown(struct of_device *op) ++static int ohci_hcd_ppc_of_shutdown(struct of_device *op) +{ + struct usb_hcd *hcd = dev_get_drvdata(&op->dev); + @@ -271,9 +296,6 @@ index 0000000..30ce520 + return 0; +} + -+/* -+ * -+*/ + +static struct of_device_id ohci_hcd_ppc_of_match[] = { +#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE @@ -298,37 +320,21 @@ index 0000000..30ce520 +#endif + {}, +}; ++MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match); + -+static int __devinit -+ohci_hcd_ppc_of_drv_probe(struct of_device *op, const struct of_device_id *match) -+{ -+ struct device_node *dev; -+ int ret; -+ int is_bigendian; ++#if !defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \ ++ !defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE) ++#error "No endianess selected for ppc-of-ohci" ++#endif + -+ if (usb_disabled()) -+ return -ENODEV; -+ -+ dev = op->node; -+ is_bigendian = 0; -+ -+ if ( device_is_compatible(dev, "ohci-bigendian") ) -+ is_bigendian = 1; -+ -+ if ( device_is_compatible(dev, "ohci-be") ) -+ is_bigendian = 1; -+ -+ ret = usb_hcd_ppc_of_probe(&ohci_ppc_of_hc_driver, op, is_bigendian); -+ return ret; -+} + +static struct of_platform_driver ohci_hcd_ppc_of_driver = { + .name = "ppc-of-ohci", + .match_table = ohci_hcd_ppc_of_match, -+ .probe = ohci_hcd_ppc_of_drv_probe, -+ .remove = ohci_hcd_ppc_of_drv_remove, -+ .shutdown = ohci_hcd_ppc_of_drv_shutdown, -+#ifdef CONFIG_PM ++ .probe = ohci_hcd_ppc_of_probe, ++ .remove = ohci_hcd_ppc_of_remove, ++ .shutdown = ohci_hcd_ppc_of_shutdown, ++#ifdef CONFIG_PM + /*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/ + /*.resume = ohci_hcd_ppc_soc_drv_resume,*/ +#endif @@ -338,23 +344,6 @@ index 0000000..30ce520 + }, +}; + -+static int __init ohci_hcd_ppc_of_init(void) -+{ -+ pr_debug(DRIVER_INFO " (PPC OF)\n"); -+ pr_debug("block sizes: ed %d td %d\n", sizeof(struct ed), -+ sizeof(struct td)); -+ -+ return of_register_platform_driver(&ohci_hcd_ppc_of_driver); -+} -+ -+static void __exit ohci_hcd_ppc_of_cleanup(void) -+{ -+ of_unregister_platform_driver(&ohci_hcd_ppc_of_driver); -+} -+ -+module_init(ohci_hcd_ppc_of_init); -+module_exit(ohci_hcd_ppc_of_cleanup); -+ -- -1.4.3.2 +1.4.4.2 diff --git a/debian/patches/features/powerpc/efika/0010-Add-Efika-platform.diff b/debian/patches/features/powerpc/efika/0010-Add-Efika-platform.diff deleted file mode 100644 index 8a51cca01..000000000 --- a/debian/patches/features/powerpc/efika/0010-Add-Efika-platform.diff +++ /dev/null @@ -1,1898 +0,0 @@ -From 6a9d4efc825b36726e94ecfe9e642cc923cb6d78 Mon Sep 17 00:00:00 2001 -From: Nicolas DET -Date: Fri, 24 Nov 2006 13:33:48 +0100 -Subject: [PATCH] Add Efika platform - -Signed-off-by: Nicolas DET ---- - arch/powerpc/Kconfig | 8 + - arch/powerpc/boot/Makefile | 1 + - arch/powerpc/platforms/Makefile | 1 + - arch/powerpc/platforms/efika/Makefile | 1 + - arch/powerpc/platforms/efika/bestcomm.h | 488 +++++++++++++ - arch/powerpc/platforms/efika/efika.h | 19 + - arch/powerpc/platforms/efika/mpc52xx_bestcomm.c | 715 ++++++++++++++++++++ - .../platforms/efika/mpc52xx_bestcomm_helper.c | 299 ++++++++ - arch/powerpc/platforms/efika/pci.c | 119 ++++ - arch/powerpc/platforms/efika/setup.c | 150 ++++ - 10 files changed, 1801 insertions(+), 0 deletions(-) - -diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig -index 0673dbe..32a128d 100644 ---- a/arch/powerpc/Kconfig -+++ b/arch/powerpc/Kconfig -@@ -386,6 +386,14 @@ config PPC_CHRP - select PPC_UDBG_16550 - default y - -+config PPC_EFIKA -+ bool "bPlan Efika 5k2. MPC5200B based computer" -+ depends on PPC_MULTIPLATFORM && PPC32 -+ select PPC_RTAS -+ select RTAS_PROC -+ select PPC_MPC52xx -+ default y -+ - config PPC_PMAC - bool "Apple PowerMac based machines" - depends on PPC_MULTIPLATFORM -diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile -index 4b2be61..7b8ce5e 100644 ---- a/arch/powerpc/boot/Makefile -+++ b/arch/powerpc/boot/Makefile -@@ -155,6 +155,7 @@ image-$(CONFIG_PPC_PSERIES) += zImage.p - image-$(CONFIG_PPC_MAPLE) += zImage.pseries - image-$(CONFIG_PPC_IBM_CELL_BLADE) += zImage.pseries - image-$(CONFIG_PPC_CHRP) += zImage.chrp -+image-$(CONFIG_PPC_EFIKA) += zImage.chrp - image-$(CONFIG_PPC_PMAC) += zImage.pmac - image-$(CONFIG_DEFAULT_UIMAGE) += uImage - -diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile -index e58fa95..8294fe4 100644 ---- a/arch/powerpc/platforms/Makefile -+++ b/arch/powerpc/platforms/Makefile -@@ -6,6 +6,7 @@ obj-$(CONFIG_PPC_PMAC) += powermac/ - endif - endif - obj-$(CONFIG_PPC_CHRP) += chrp/ -+obj-$(CONFIG_PPC_EFIKA) += efika/ - obj-$(CONFIG_4xx) += 4xx/ - obj-$(CONFIG_PPC_83xx) += 83xx/ - obj-$(CONFIG_PPC_85xx) += 85xx/ -diff --git a/arch/powerpc/platforms/efika/Makefile b/arch/powerpc/platforms/efika/Makefile -new file mode 100644 -index 0000000..5aefd3d ---- /dev/null -+++ b/arch/powerpc/platforms/efika/Makefile -@@ -0,0 +1 @@ -+obj-y += setup.o pci.o mpc52xx_bestcomm.o mpc52xx_bestcomm_helper.o -diff --git a/arch/powerpc/platforms/efika/bestcomm.h b/arch/powerpc/platforms/efika/bestcomm.h -new file mode 100644 -index 0000000..9555c1b ---- /dev/null -+++ b/arch/powerpc/platforms/efika/bestcomm.h -@@ -0,0 +1,488 @@ -+/* -+ * include/asm-powerpc/Bestcomm.h -+ * -+ * Driver for MPC52xx processor BestComm peripheral controller -+ * Using bplan GmbH OpenFirmware -+ * -+ * 2006 (c) bplan GmbH 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. -+ * -+ */ -+ -+#ifndef __BESTCOMM_BESTCOMM_H__ -+#define __BESTCOMM_BESTCOMM_H__ -+ -+ -+/**************/ -+/**************/ -+/**************/ -+ -+#include -+#include -+ -+#include -+ -+/**************/ -+/**************/ -+/**************/ -+ -+#define BESTCOMM_MAX_VAR 24 -+#define BESTCOMM_MAX_INC 8 -+#define BESTCOMM_MAX_TASKS 16 -+ -+/**************/ -+/**************/ -+/**************/ -+ -+/* Task Descriptor Table Entry */ -+/* copied from bestcomm.h, can be found in the public freescale doc */ -+ -+/* pragma pack required ? */ -+struct bestcomm_tdt { -+ u32 start; -+ u32 stop; -+ u32 var; -+ u32 fdt; -+ u32 exec_status; /* used internally by SmartComm engine */ -+ u32 mvtp; /* used internally by SmartComm engine */ -+ u32 context; -+ u32 litbase; -+}; -+ -+struct bestcomm_taskhandle -+{ -+ int taskid; -+ int irq; -+ -+ struct bestcomm_tdt __iomem * bestcomm_tdt; -+ -+ u32 __iomem *bestcomm_taskcode; -+ u32 __iomem *bestcomm_vartable; -+ -+ union { -+ struct sdma_bd *bd; -+ struct sdma_bd2 *bd2; -+ }; -+ -+ void **cookie; -+ u16 index; -+ u16 outdex; -+ u16 num_bd; -+ u32 flags; -+}; -+ -+ -+/**************/ -+struct bestcomm_mainhandle -+{ -+ struct device_node *buildin_ofwnode; -+ struct device_node *sram_ofwnode; -+ struct device_node *bestcomm_ofwnode; -+ -+ int bestcomm_irq; -+ -+ unsigned long sdma_io_basebus; -+ struct mpc52xx_sdma __iomem* sdma_io_basevirt; -+ size_t sdma_io_size; -+ -+ struct bestcomm_tdt __iomem *sdma_tdtentry; -+ -+ unsigned long sram_basebus; -+ void __iomem* sram_basevirt; -+ size_t sram_size; -+ size_t sram_available; -+ -+ struct bestcomm_taskhandle taskhandle_table[BESTCOMM_MAX_TASKS]; -+}; -+ -+ -+ -+/**************/ -+/**************/ -+/**************/ -+int -+bestcomm_init_once(void); -+ -+struct device_node * -+bestcomm_find_hw(char *name); -+ -+int -+bestcomm_hwiscapable(void); -+ -+u32 -+bestcomm_getreg(char *name, int *size); -+ -+int -+bestcomm_getintrvector(char *name); -+ -+/**************/ -+struct bestcomm_taskhandle * -+bestcomm_taskallocate(int bestcomm_tasknum, int queue_size); -+ -+void -+bestcomm_taskfree(struct bestcomm_taskhandle *mytaskhandle); -+ -+int -+bestcomm_taskclear_irq(struct bestcomm_taskhandle *mytaskhandle); -+ -+int -+bestcomm_taskenable(struct bestcomm_taskhandle *mytaskhandle); -+ -+int -+bestcomm_taskdisable(struct bestcomm_taskhandle *mytaskhandle); -+ -+int -+bestcomm_taskget_irq(struct bestcomm_taskhandle *mytaskhandle); -+ -+u32 __iomem* -+bestcomm_taskget_code(struct bestcomm_taskhandle *mytaskhandle); -+ -+u32 __iomem* -+bestcomm_taskget_vartable(struct bestcomm_taskhandle *mytaskhandle); -+ -+u32 __iomem* -+bestcomm_taskget_inctable(struct bestcomm_taskhandle *mytaskhandle); -+ -+u16 __iomem* -+bestcomm_taskget_tcr(struct bestcomm_taskhandle *mytaskhandle); -+ -+void __iomem * -+bestcomm_phys_to_virt(struct bestcomm_mainhandle *mymainhandle, unsigned long busaddr); -+ -+unsigned long -+bestcomm_virt_to_phys(struct bestcomm_mainhandle *mymainhandle, void *virtaddr); -+ -+void __iomem* -+bestcomm_sram_alloc(struct bestcomm_taskhandle *mytaskhandle, int len, unsigned long *busaddr); -+ -+void -+bestcomm_sram_free(struct bestcomm_taskhandle *mytaskhandle, void *ptr, int len); -+ -+/**************/ -+/* -+ * The original Linux API has been here partially copied or wrapped -+ * this way, it's quiet easy to reuse exising code -+*/ -+/* Buffer Descriptor definitions */ -+struct sdma_bd { -+ u32 status; -+ void *data; -+}; -+ -+struct sdma_bd2 { -+ u32 status; -+ void *data1; -+ void *data2; -+}; -+ -+#define FIELD_OFFSET(s,f) ((unsigned long)(&(((struct s*)0)->f))) -+ -+#define SDMA_FLAGS_NONE 0x0000 -+#define SDMA_FLAGS_ENABLE_TASK 0x0001 -+#define SDMA_FLAGS_BD2 0x0002 -+#define SDMA_BD_READY 0x40000000UL -+ -+#define SDMA_FEC_TX_BD_TFD 0x08000000UL /* transmit frame done */ -+#define SDMA_FEC_TX_BD_INT 0x04000000UL /* Interrupt */ -+#define SDMA_FEC_TX_BD_TFD_INIT (SDMA_BD_READY | SDMA_FEC_TX_BD_TFD | SDMA_FEC_TX_BD_INT) -+ -+#define SDMA_LEN_BITS 26 -+#define SDMA_LEN_MASK ((1 << SDMA_LEN_BITS) - 1) -+ -+#define SDMA_BD_ALIGN 0x10 -+ -+/**************/ -+/**************/ -+/**************/ -+struct sdma { struct bestcomm_taskhandle taskhandle; }; -+ -+/**************/ -+/**************/ -+/**************/ -+unsigned long -+sdma_sram_pa(void __iomem *virt); -+ -+void __iomem * -+sdma_sram_va(unsigned long pa); -+ -+unsigned long sdma_io_pa -+(void __iomem *virt); -+ -+void __iomem * -+sdma_io_va(unsigned long pa); -+ -+/**************/ -+struct sdma * -+sdma_fex_tx_preinit(int bdnum); -+ -+struct sdma * -+sdma_fex_rx_preinit(int bdnum); -+ -+extern int -+sdma_fec_rx_init(struct sdma *s, phys_addr_t fifo, int maxbufsize); -+ -+extern int -+sdma_fec_tx_init(struct sdma *s, phys_addr_t fifo); -+ -+struct sdma * -+sdma_ata_preinit(int maxbuffers); -+ -+int -+sdma_ata_init(struct bestcomm_taskhandle *mytaskhandle, int maxbufsize); -+ -+struct sdma_ata_var { -+ u32 enable; /* (u16*) address of task's control register */ -+ u32 bd_base; /* (struct sdma_bd*) beginning of ring buffer */ -+ u32 bd_last; /* (struct sdma_bd*) end of ring buffer */ -+ u32 bd_start; /* (struct sdma_bd*) current bd */ -+ u32 buffer_size; /* size of receive buffer */ -+}; -+ -+/**************/ -+/* ata task incs that need to be set before enabling the task */ -+struct sdma_ata_inc { -+ u16 pad0; -+ s16 incr_bytes; -+ u16 pad1; -+ s16 incr_dst; -+ u16 pad2; -+ s16 incr_src; -+}; -+ -+/* rx task vars that need to be set before enabling the task */ -+struct sdma_fec_rx_var { -+ u32 enable; /* (u16*) address of task's control register */ -+ u32 fifo; /* (u32*) address of fec's fifo */ -+ u32 bd_base; /* (struct sdma_bd*) beginning of ring buffer */ -+ u32 bd_last; /* (struct sdma_bd*) end of ring buffer */ -+ u32 bd_start; /* (struct sdma_bd*) current bd */ -+ u32 buffer_size; /* size of receive buffer */ -+}; -+ -+/* rx task incs that need to be set before enabling the task */ -+struct sdma_fec_rx_inc { -+ u16 pad0; -+ s16 incr_bytes; -+ u16 pad1; -+ s16 incr_dst; -+ u16 pad2; -+ s16 incr_dst_ma; -+}; -+ -+/* tx task vars that need to be set before enabling the task */ -+struct sdma_fec_tx_var { -+ u32 DRD; /* (u32*) address of self-modified DRD */ -+ u32 fifo; /* (u32*) address of fec's fifo */ -+ u32 enable; /* (u16*) address of task's control register */ -+ u32 bd_base; /* (struct sdma_bd*) beginning of ring buffer */ -+ u32 bd_last; /* (struct sdma_bd*) end of ring buffer */ -+ u32 bd_start; /* (struct sdma_bd*) current bd */ -+ u32 buffer_size; /* set by uCode for each packet */ -+}; -+ -+/* tx task incs that need to be set before enabling the task */ -+struct sdma_fec_tx_inc { -+ u16 pad0; -+ s16 incr_bytes; -+ u16 pad1; -+ s16 incr_src; -+ u16 pad2; -+ s16 incr_src_ma; -+}; -+/**************/ -+void * -+sdma_sram_alloc(int size, int alignment, u32 *dma_handle); -+ -+static inline struct sdma * -+sdma_alloc(int request_queue_size) -+{ return NULL; }; -+ -+static inline void -+sdma_free(struct sdma *s) -+{ bestcomm_taskfree( (struct bestcomm_taskhandle *)s); } -+ -+static inline int -+sdma_irq(struct sdma *s) -+{ return bestcomm_taskget_irq(&s->taskhandle); } -+ -+static inline void -+sdma_enable(struct sdma *s) -+{ bestcomm_taskenable(&s->taskhandle); } -+ -+static inline void -+sdma_disable(struct sdma *s) -+{ bestcomm_taskdisable(&s->taskhandle); } -+ -+static inline int -+sdma_queue_empty(struct sdma *s_) -+{ -+ struct bestcomm_taskhandle *s = &s_->taskhandle; -+ return s->index == s->outdex; -+} -+ -+static inline void -+sdma_clear_irq(struct sdma *s) -+{ bestcomm_taskclear_irq( &s->taskhandle); } -+ -+static inline int -+sdma_next_index(struct sdma *s_) -+{ -+ struct bestcomm_taskhandle *s = &s_->taskhandle; -+ return ((s->index + 1) == s->num_bd) ? 0 : s->index + 1; -+} -+ -+static inline int -+sdma_next_outdex(struct sdma *s_) -+{ -+ struct bestcomm_taskhandle *s = &s_->taskhandle; -+ return ((s->outdex + 1) == s->num_bd) ? 0 : s->outdex + 1; -+} -+ -+static inline int -+sdma_queue_full(struct sdma *s_) -+{ -+ struct bestcomm_taskhandle *s = &s_->taskhandle; -+ return s->outdex == sdma_next_index(s_); -+} -+ -+static inline int -+sdma_buffer_done(struct sdma *s_) -+{ -+ struct bestcomm_taskhandle *s = &s_->taskhandle; -+ -+ if (sdma_queue_empty(s_)) -+ return 0; -+ -+ rmb(); -+ return (s->bd[s->outdex].status & SDMA_BD_READY) == 0; -+} -+ -+static inline int -+sdma_buffer_done_fixed(struct sdma *s_) -+{ -+ struct bestcomm_taskhandle *s = &s_->taskhandle; -+ rmb(); -+ return (s->bd[s->outdex].status & SDMA_BD_READY) == 0; -+} -+ -+static inline int -+sdma_buffer2_done(struct sdma *s_) -+{ -+ struct bestcomm_taskhandle *s = &s_->taskhandle; -+ -+ if (sdma_queue_empty(s_)) -+ return 0; -+ -+ rmb(); -+ return (s->bd2[s->outdex].status & SDMA_BD_READY) == 0; -+} -+ -+static inline void -+sdma_submit_buffer(struct sdma *s_, void *cookie, void *data, int length) -+{ -+ struct bestcomm_taskhandle *s = &s_->taskhandle; -+ -+ s->cookie[s->index] = cookie; -+ s->bd[s->index].data = data; -+ wmb(); -+ s->bd[s->index].status = SDMA_BD_READY | length; -+ s->index = sdma_next_index(s_); -+ if (s->flags & SDMA_FLAGS_ENABLE_TASK) -+ bestcomm_taskenable(s); -+} -+ -+/* -+ * Special submit_buffer function to submit last buffer of a frame to -+ * the FEC tx task. tfd means "transmit frame done". -+ */ -+static inline void -+sdma_fec_tfd_submit_buffer(struct sdma *s_, void *cookie, void *data, int length) -+{ -+ struct bestcomm_taskhandle *s = &s_->taskhandle; -+ -+ s->cookie[s->index] = cookie; -+ s->bd[s->index].data = data; -+ wmb(); -+ s->bd[s->index].status = SDMA_FEC_TX_BD_TFD_INIT | length; -+ s->index = sdma_next_index(s_); -+ bestcomm_taskenable(s); -+} -+ -+static inline void * -+sdma_retrieve_buffer(struct sdma *s_, int *length) -+{ -+ struct bestcomm_taskhandle *s = &s_->taskhandle; -+ void *cookie = s->cookie[s->outdex]; -+ -+ if (length) { -+ rmb(); -+ *length = s->bd[s->outdex].status & SDMA_LEN_MASK; -+ } -+ s->outdex = sdma_next_outdex(s_); -+ return cookie; -+} -+ -+static inline void -+sdma_reset_buffers(struct sdma *s_) -+{ -+ struct bestcomm_taskhandle *s = &s_->taskhandle; -+ -+ while (!sdma_queue_empty(s_)) { -+ s->bd[s->outdex].status = 0; -+ wmb(); -+ s->bd[s->outdex].data = 0; -+ sdma_retrieve_buffer(s_, NULL); -+ } -+ s->index = s->outdex = 0; -+} -+ -+static inline void -+sdma_submit_buffer2(struct sdma *s_, void *cookie, -+ void *data1, void *data2, int length) -+{ -+ struct bestcomm_taskhandle *s = &s_->taskhandle; -+ -+ s->cookie[s->index] = cookie; -+ s->bd2[s->index].data1 = data1; -+ s->bd2[s->index].data2 = data2; -+ wmb(); -+ s->bd2[s->index].status = SDMA_BD_READY | length; -+ s->index = sdma_next_index(s_); -+ if (s->flags & SDMA_FLAGS_ENABLE_TASK) -+ bestcomm_taskenable(s); -+} -+ -+static inline void * -+sdma_retrieve_buffer2(struct sdma *s_, int *length) -+{ -+ struct bestcomm_taskhandle *s = &s_->taskhandle; -+ void *cookie = s->cookie[s->outdex]; -+ -+ if (length) { -+ rmb(); -+ *length = s->bd2[s->outdex].status & SDMA_LEN_MASK; -+ } -+ -+ s->outdex = sdma_next_outdex(s_); -+ return cookie; -+} -+ -+static inline void -+sdma_reset_buffers2(struct sdma *s_) -+{ -+ struct bestcomm_taskhandle *s = &s_->taskhandle; -+ while (!sdma_queue_empty(s_)) { -+ s->bd2[s->outdex].status = 0; -+ s->bd2[s->outdex].data1 = 0; -+ s->bd2[s->outdex].data2 = 0; -+ wmb(); -+ sdma_retrieve_buffer2(s_, NULL); -+ } -+ -+ s->index = s->outdex = 0; -+} -+ -+#endif -+ -diff --git a/arch/powerpc/platforms/efika/efika.h b/arch/powerpc/platforms/efika/efika.h -new file mode 100644 -index 0000000..2f060fd ---- /dev/null -+++ b/arch/powerpc/platforms/efika/efika.h -@@ -0,0 +1,19 @@ -+/* -+ * Efika 5K2 platform setup - Header file -+ * -+ * Copyright (C) 2006 bplan GmbH -+ * -+ * 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. -+ * -+ */ -+ -+#ifndef __ARCH_POWERPC_EFIKA__ -+#define __ARCH_POWERPC_EFIKA__ -+ -+#define EFIKA_PLATFORM_NAME "Efika" -+ -+extern void __init efika_pcisetup(void); -+ -+#endif -diff --git a/arch/powerpc/platforms/efika/mpc52xx_bestcomm.c b/arch/powerpc/platforms/efika/mpc52xx_bestcomm.c -new file mode 100644 -index 0000000..c573aed ---- /dev/null -+++ b/arch/powerpc/platforms/efika/mpc52xx_bestcomm.c -@@ -0,0 +1,715 @@ -+/* -+ * arch/powerpc/platforms/mpc52xx_bestcomm.c -+ * -+ * Driver for MPC52xx processor BestComm peripheral controller -+ * Using bplan GmbH OpenFirmware -+ * -+ * 2006 (c) bplan GmbH 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. -+ * -+ */ -+ -+#undef DEBUG -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "bestcomm.h" -+ -+/**************/ -+/**************/ -+/**************/ -+ -+struct bestcomm_mainhandle bestcomm_mainhandle; -+ -+static int opencnt = 0; -+static struct bestcomm_taskhandle *mysdma_alloc(struct bestcomm_taskhandle *mytaskhandle, int queue_size); -+ -+/**************/ -+/**************/ -+/**************/ -+ -+typedef u32 Cell; -+ -+/* -+ * Virtutal <-> Bus address translator -+ * everything is static inlien here -+*/ -+ -+/**************/ -+static void __iomem * -+sram_bustovirt(struct bestcomm_mainhandle *mymainhandle, unsigned long busaddr) -+{ -+ void __iomem *virtaddr; -+ long offset; -+ -+ offset = busaddr - mymainhandle->sram_basebus; -+ -+ if (offset < 0) -+ return NULL; -+ -+ if (offset > mymainhandle->sram_size) -+ return NULL; -+ -+ virtaddr = (void __iomem *) ( (u8 *)mymainhandle->sram_basevirt + offset); -+ -+ return virtaddr; -+} -+ -+static unsigned long -+sram_virttobus(struct bestcomm_mainhandle *mymainhandle, void *virtaddr) -+{ -+ unsigned long busaddr; -+ long offset; -+ -+ offset = (u8 *) virtaddr - (u8 *) mymainhandle->sram_basevirt; -+ -+ if (offset < 0) -+ return 0; -+ -+ if (offset > mymainhandle->sram_size) -+ return 0; -+ -+ busaddr = mymainhandle->sram_basebus + offset; -+ -+ return busaddr; -+} -+ -+static void __iomem * -+io_bustovirt(struct bestcomm_mainhandle *mymainhandle, unsigned long busaddr) -+{ -+ void __iomem *virtaddr; -+ long offset; -+ -+ offset = busaddr - mymainhandle->sdma_io_basebus; -+ -+ if (offset < 0) -+ return NULL; -+ -+ if (offset > mymainhandle->sdma_io_size) -+ return NULL; -+ -+ virtaddr = (void __iomem *) ( (u8 *)mymainhandle->sdma_io_basevirt + offset); -+ -+ return virtaddr; -+} -+ -+static unsigned long -+io_virttobus(struct bestcomm_mainhandle *mymainhandle, void *virtaddr) -+{ -+ unsigned long busaddr; -+ long offset; -+ -+ offset = (u8 *) virtaddr - (u8 *) mymainhandle->sdma_io_basevirt; -+ -+ if (offset < 0) -+ return 0; -+ -+ if (offset > mymainhandle->sdma_io_size) -+ return 0; -+ -+ busaddr = mymainhandle->sdma_io_basebus + offset; -+ -+ return busaddr; -+} -+ -+/**************/ -+static u8 *area1_end; -+static u8 *area2_begin; -+static spinlock_t sdma_lock = SPIN_LOCK_UNLOCKED; -+ -+void * -+sdma_sram_alloc(int size, int alignment, u32 *dma_handle) -+{ -+ u8 *a; -+ -+ spin_lock(&sdma_lock); -+ -+ /* alignment must be a power of 2 */ -+ BUG_ON(alignment & (alignment - 1)); -+ -+ if (alignment < 16) { -+ a = (u8 *)(((u32)area1_end + (alignment-1)) & ~(alignment-1)); -+ if (a + size <= area2_begin) -+ area1_end = a + size; -+ else -+ a = 0; /* out of memory */ -+ } else { -+ a = (u8 *)(((u32)area2_begin - size) & ~(alignment - 1)); -+ if (a >= area1_end) -+ area2_begin = a; -+ else -+ a = 0; /* out of memory */ -+ } -+ if(a && dma_handle) -+ *dma_handle = sdma_sram_pa(a); -+ spin_unlock(&sdma_lock); -+ return (void *)a; -+} -+ -+void __iomem* -+bestcomm_sram_alloc(struct bestcomm_taskhandle *mytaskhandle, int len, unsigned long *busaddr) -+{ -+ void *virtaddr; -+ u32 lbusaddr=0; -+ -+ virtaddr = sdma_sram_alloc(len, 32, &lbusaddr); -+ *busaddr = (unsigned long) lbusaddr; -+ -+ return virtaddr; -+} -+ -+/**************/ -+void -+bestcomm_sram_free(struct bestcomm_taskhandle *mytaskhandle, void *ptr, int len) -+{ -+} -+ -+/**************/ -+static int probemisc(struct bestcomm_mainhandle *mymainhandle) -+{ -+ int interrupt; -+ interrupt = 0xc0; -+ mymainhandle->bestcomm_irq = interrupt; -+ return 0; -+} -+ -+/**************/ -+static int -+probeavailable_sram(struct bestcomm_mainhandle *mymainhandle) -+{ -+ struct device_node *sram_ofwnode; -+ Cell *oneptr; -+ int proplen; -+ int nac; -+ int nsc; -+ int onepair_size; -+ int paircount; -+ int i; -+ -+ int pair_size; -+ unsigned long pair_addr; -+ -+ int biggestpair_size=0; -+ unsigned long biggestpair_addr=0; -+ -+ pr_debug("\n"); -+ -+ sram_ofwnode = mymainhandle->sram_ofwnode; -+ nac = prom_n_addr_cells(sram_ofwnode); -+ nsc = prom_n_size_cells(sram_ofwnode); -+ onepair_size = nac + nsc; -+ -+ oneptr = (Cell *) get_property(sram_ofwnode, "available", &proplen); -+ if (!oneptr) -+ return -1; -+ -+ paircount = proplen / (sizeof(Cell) * onepair_size); -+ -+ for(i=0; i < paircount; i++) -+ { -+ pair_addr = (unsigned long) oneptr[i * onepair_size]; -+ pair_size = (int) oneptr[i * onepair_size + nac]; -+ -+ mymainhandle->sram_available += pair_size; -+ -+ pr_debug("SRAM free at 0x%8.8lx, size=%d\n", pair_addr, pair_size); -+ -+ if (pair_size>biggestpair_size) { -+ biggestpair_size = pair_size; -+ biggestpair_addr = pair_addr; -+ } -+ } -+ -+ area1_end = sram_bustovirt(mymainhandle, biggestpair_addr); -+ area2_begin = sram_bustovirt(mymainhandle, biggestpair_addr + biggestpair_size); -+ -+ pr_debug("SRAM area %p -> %p\n", area1_end, area2_begin); -+ -+ return 0; -+} -+ -+/**************/ -+static int -+mapsram(struct bestcomm_mainhandle *mymainhandle) -+{ -+ unsigned long sram_offset; -+ int sram_size; -+ void *__iomem sram_virtmem; -+ -+ sram_size = mymainhandle->sram_size; -+ sram_offset = mymainhandle->sram_basebus; -+ -+ sram_virtmem = ioremap_nocache(sram_offset, sram_size); -+ if (!sram_virtmem) -+ return -1; -+ -+ mymainhandle->sram_basevirt = sram_virtmem; -+ -+ pr_debug("SRAM mapped at %p\n", sram_virtmem); -+ -+ return 0; -+} -+ -+/**************/ -+static int -+probesram(struct bestcomm_mainhandle *mymainhandle) -+{ -+ struct device_node *onenode; -+ Cell *oneptr; -+ int proplen; -+ int nac; -+ int nsc; -+ -+ unsigned long sram_offset; -+ int sram_size; -+ -+ pr_debug("\n"); -+ -+ onenode = of_find_compatible_node(NULL, "memory", "mpc5200-sram"); -+ if (!onenode) -+ return -1; -+ -+ nac = prom_n_addr_cells(onenode); -+ nsc = prom_n_size_cells(onenode); -+ -+ pr_debug("nac=%d, nsc=%d\n", nac, nsc); -+ -+ oneptr = (Cell *) get_property(onenode, "reg", &proplen); -+ if (!oneptr) -+ return -1; -+ -+ if (proplen < 2) -+ return -1; -+ -+ sram_offset = (unsigned long) oneptr[0]; -+ sram_size = (int) oneptr[nac]; -+ -+ pr_debug("oneptr=%p. %lx %d\n", oneptr, sram_offset , sram_size); -+ -+ mymainhandle->sram_size = sram_size; -+ mymainhandle->sram_basebus = sram_offset; -+ mymainhandle->sram_ofwnode = onenode; -+ -+ return 0; -+} -+ -+/**************/ -+static int -+probetasktable(struct bestcomm_mainhandle *mymainhandle) -+{ -+ struct device_node *onenode; -+ Cell *oneptr; -+ int proplen; -+ int nac; -+ unsigned long tdt_busaddr; -+ long tdt_offset; -+ int tdt_size; -+ -+ pr_debug("\n"); -+ -+ onenode = mymainhandle->bestcomm_ofwnode; -+ oneptr = (Cell *) get_property(onenode, "bestcomm_tasktable", &proplen); -+ if (!oneptr) -+ return -1; -+ -+ if (proplen < 2) -+ return -1; -+ -+ nac = prom_n_addr_cells(onenode); -+ -+ tdt_busaddr = (unsigned long) oneptr[0]; -+ tdt_size = (int) oneptr[nac]; -+ -+ tdt_offset = tdt_busaddr - mymainhandle->sram_basebus; -+ -+ pr_debug("tdt_busaddr=%8.8lx, tdt_size=%d, tdt_offset=%ld \n", tdt_busaddr, tdt_size, tdt_offset); -+ -+ if (tdt_offset < 0) -+ return -1; -+ -+ if (tdt_offset > mymainhandle->sram_size) -+ return -1; -+ -+ mymainhandle->sdma_tdtentry = (struct bestcomm_tdt __iomem *) ( (u8 *)mymainhandle->sram_basevirt + tdt_offset); -+ -+ pr_debug("SDMA_TDTEntry =%p\n", mymainhandle->sdma_tdtentry); -+ -+ return 0; -+} -+ -+/**************/ -+static int -+probeio(struct bestcomm_mainhandle *mymainhandle) -+{ -+ struct device_node *onenode; -+ Cell *oneptr; -+ int proplen; -+ int nac; -+ int nsc; -+ -+ unsigned long io_busaddr; -+ int io_size; -+ -+ pr_debug("\n"); -+ -+ onenode = of_find_compatible_node(NULL, "dma-controller", "mpc5200-bestcomm"); -+ if (!onenode) -+ return -1; -+ -+ nac = prom_n_addr_cells(onenode); -+ nsc = prom_n_size_cells(onenode); -+ -+ pr_debug("nac=%d, nsc=%d\n", nac, nsc); -+ -+ oneptr = (Cell *) get_property(onenode, "reg", &proplen); -+ if (!oneptr) -+ return -1; -+ -+ if (proplen < 2) -+ return -1; -+ -+ io_busaddr = (unsigned long) oneptr[0]; -+ io_size = (int) oneptr[nac]; -+ -+ pr_debug("oneptr=%p. %lx %d\n", oneptr, io_busaddr , io_size); -+ mymainhandle->sdma_io_size = io_size; -+ mymainhandle->sdma_io_basebus = io_busaddr; -+ mymainhandle->bestcomm_ofwnode = onenode; -+ -+ return 0; -+} -+ -+/**************/ -+static int -+mapio(struct bestcomm_mainhandle *mymainhandle) -+{ -+ unsigned long io_busaddr; -+ void __iomem *io_virtaddr; -+ int io_size; -+ -+ io_busaddr = mymainhandle->sdma_io_basebus; -+ io_size = mymainhandle->sdma_io_size; -+ -+ io_virtaddr = ioremap_nocache(io_busaddr, io_size); -+ if (!io_virtaddr) -+ goto fail; -+ -+ mymainhandle->sdma_io_basevirt = io_virtaddr; -+ -+ pr_debug("Bestcomm mapped at %p\n", io_virtaddr ); -+ -+ return 0; -+ -+fail: -+ return -1; -+} -+ -+ -+/**************/ -+static int -+do_bestcomminit(struct bestcomm_mainhandle *mymainhandle) -+{ -+ int ret; -+ -+ ret = probeio(mymainhandle); -+ if (ret<0) -+ goto fail; -+ -+ ret = mapio(mymainhandle); -+ if (ret<0) -+ goto fail; -+ -+ ret = probesram(mymainhandle); -+ if (ret<0) -+ goto fail; -+ -+ ret = mapsram(mymainhandle); -+ if (ret<0) -+ goto fail; -+ -+ ret = probeavailable_sram(mymainhandle); -+ if (ret<0) -+ goto fail; -+ -+ ret = probetasktable(mymainhandle); -+ if (ret<0) -+ goto fail; -+ -+ ret = probemisc(mymainhandle); -+ if (ret<0) -+ goto fail; -+ -+ return 0; -+ -+fail: -+ return -1; -+} -+ -+/**************/ -+int -+bestcomm_hwiscapable(void) -+{ -+ return bestcomm_mainhandle.buildin_ofwnode != NULL; -+} -+ -+/**************/ -+/* -+ * Entry, should be called when the CPU is running -+ * on an OFW machine. -+ * We will silently and properly failed if no compatible -+ * hardware (MPC5200, MPC5200b yet) -+*/ -+int -+bestcomm_init_once(void) -+{ -+ int ret; -+ -+ pr_debug("opencnt %d\n", opencnt); -+ -+ /* Already inited ? */ -+ if (opencnt>0) -+ return 0; -+ -+ memset(&bestcomm_mainhandle, 0x00, sizeof(bestcomm_mainhandle) ); -+ -+ ret = do_bestcomminit(&bestcomm_mainhandle); -+ if (ret<0) -+ return -1; -+ -+ opencnt++; -+ -+ printk(KERN_INFO "MPC52xx/OpenFirmware: %d kB of free SRAM\n", bestcomm_mainhandle.sram_available ); -+ -+ return 0; -+} -+ -+/**************/ -+/**************/ -+/**************/ -+void -+bestcomm_taskfree(struct bestcomm_taskhandle *mytaskhandle) -+{ -+ if (mytaskhandle) -+ { -+ kfree(mytaskhandle->cookie); -+ mytaskhandle->cookie = NULL; -+ } -+} -+ -+struct bestcomm_taskhandle * -+bestcomm_taskallocate(int bestcomm_tasknum, int queue_size) -+{ -+ struct bestcomm_taskhandle *mytaskhandle; -+ struct bestcomm_tdt __iomem *bestcomm_tdt; -+ -+ if (bestcomm_tasknum<0) -+ return NULL; -+ -+ if (bestcomm_tasknum>=BESTCOMM_MAX_TASKS) -+ return NULL; -+ -+ mytaskhandle = &bestcomm_mainhandle.taskhandle_table[bestcomm_tasknum]; -+ -+ pr_debug("bestcomm_tasknum %d\n", bestcomm_tasknum); -+ -+ bestcomm_tdt = &bestcomm_mainhandle.sdma_tdtentry[bestcomm_tasknum]; -+ -+ mytaskhandle->taskid = bestcomm_tasknum; -+ mytaskhandle->bestcomm_taskcode = sram_bustovirt(&bestcomm_mainhandle, bestcomm_tdt->start); -+ mytaskhandle->bestcomm_vartable = sram_bustovirt(&bestcomm_mainhandle, bestcomm_tdt->var); -+ mytaskhandle->irq = bestcomm_mainhandle.bestcomm_irq + bestcomm_tasknum; -+ -+ pr_debug("irq=%d\n", mytaskhandle->irq ); -+ -+ mytaskhandle = mysdma_alloc(mytaskhandle, queue_size); -+ -+ return mytaskhandle; -+} -+ -+/**************/ -+int -+bestcomm_taskenable(struct bestcomm_taskhandle *mytaskhandle) -+{ -+ int task; -+ u16 reg; -+ -+ task = mytaskhandle->taskid; -+ -+ reg = in_be16(&bestcomm_mainhandle.sdma_io_basevirt->tcr[task]); -+ out_be16(&bestcomm_mainhandle.sdma_io_basevirt->tcr[task], reg | 0x8000); -+ -+ return task; -+} -+ -+/**************/ -+int -+bestcomm_taskdisable(struct bestcomm_taskhandle *mytaskhandle) -+{ -+ int task; -+ u16 reg; -+ -+ task = mytaskhandle->taskid; -+ -+ reg = in_be16(&bestcomm_mainhandle.sdma_io_basevirt->tcr[task]); -+ out_be16(&bestcomm_mainhandle.sdma_io_basevirt->tcr[task], reg & ~0x8000); -+ -+ return task; -+} -+ -+/**************/ -+int -+bestcomm_taskclear_irq(struct bestcomm_taskhandle *mytaskhandle) -+{ -+ int tasknum = mytaskhandle->taskid; -+ out_be32(&bestcomm_mainhandle.sdma_io_basevirt->IntPend, 1 << tasknum); -+ return tasknum; -+} -+ -+/**************/ -+/**************/ -+/**************/ -+ -+ -+/**************/ -+void __iomem * -+bestcomm_phys_to_virt(struct bestcomm_mainhandle *mymainhandle, unsigned long busaddr) -+{ -+ return sram_bustovirt(mymainhandle, busaddr); -+} -+ -+unsigned long -+bestcomm_virt_to_phys(struct bestcomm_mainhandle *mymainhandle, void __iomem* virtaddr) -+{ -+ return sram_virttobus(mymainhandle, virtaddr); -+} -+ -+/**************/ -+/**************/ -+/**************/ -+ -+/* -+ * friendly helper func -+*/ -+ -+int -+bestcomm_taskget_irq(struct bestcomm_taskhandle *mytaskhandle) -+{ -+ return mytaskhandle->irq; -+} -+ -+u32 __iomem* -+bestcomm_taskget_code(struct bestcomm_taskhandle *mytaskhandle) -+{ -+ return mytaskhandle->bestcomm_taskcode; -+} -+ -+u32 __iomem* -+bestcomm_taskget_vartable(struct bestcomm_taskhandle *mytaskhandle) -+{ -+ return mytaskhandle->bestcomm_vartable; -+} -+ -+u32 __iomem* -+bestcomm_taskget_inctable(struct bestcomm_taskhandle *mytaskhandle) -+{ -+ return mytaskhandle->bestcomm_vartable + BESTCOMM_MAX_VAR; -+} -+ -+u16 __iomem* -+bestcomm_taskget_tcr(struct bestcomm_taskhandle *mytaskhandle) -+{ -+ return &bestcomm_mainhandle.sdma_io_basevirt->tcr[mytaskhandle->taskid]; -+} -+ -+ -+/**************/ -+/**************/ -+/**************/ -+/* -+ * Stuff copied and a little bit modified from the original Linux code -+ * indeed, I think it makes sense to reuse code which works. Moreover, -+ * it's then easier to reuse existing driver with SDMA task which are -+ * not in the OFW -+*/ -+ -+/**************/ -+unsigned long -+sdma_sram_pa(void __iomem *virt) -+{ -+ return sram_virttobus(&bestcomm_mainhandle, virt); -+} -+ -+void __iomem * -+sdma_sram_va(unsigned long pa) -+{ -+ return sram_bustovirt(&bestcomm_mainhandle, pa); -+} -+ -+unsigned long -+sdma_io_pa(void __iomem *virt) -+{ -+ return io_virttobus(&bestcomm_mainhandle, virt); -+} -+ -+void __iomem * -+sdma_io_va(unsigned long pa) -+{ -+ return io_bustovirt(&bestcomm_mainhandle, pa); -+} -+ -+/**************/ -+/* -+ * Here, I just alloc and setup the buffer management stuff -+ * for this task -+*/ -+static struct bestcomm_taskhandle * -+mysdma_alloc(struct bestcomm_taskhandle *mytaskhandle, int queue_size) -+{ -+ void **cookie; -+ -+ if (!mytaskhandle) -+ return NULL; -+ -+ if (queue_size) -+ { -+ cookie = kmalloc(sizeof(*cookie) * queue_size, GFP_KERNEL); -+ if (!cookie) { -+ return NULL; -+ } -+ -+ mytaskhandle->cookie = cookie; -+ } -+ -+ mytaskhandle->num_bd = queue_size; -+ return mytaskhandle; -+} -+ -+/**************/ -+/* -+ * Export symbol for modules -+*/ -+ -+EXPORT_SYMBOL(bestcomm_init_once); -+EXPORT_SYMBOL(bestcomm_hwiscapable); -+EXPORT_SYMBOL(bestcomm_taskallocate); -+EXPORT_SYMBOL(bestcomm_taskfree); -+EXPORT_SYMBOL(bestcomm_taskclear_irq); -+EXPORT_SYMBOL(bestcomm_taskenable); -+EXPORT_SYMBOL(bestcomm_taskdisable); -+EXPORT_SYMBOL(bestcomm_taskget_irq); -+EXPORT_SYMBOL(bestcomm_taskget_code); -+EXPORT_SYMBOL(bestcomm_taskget_vartable); -+EXPORT_SYMBOL(bestcomm_taskget_inctable); -+EXPORT_SYMBOL(bestcomm_taskget_tcr); -+EXPORT_SYMBOL(bestcomm_phys_to_virt); -+EXPORT_SYMBOL(bestcomm_virt_to_phys); -+EXPORT_SYMBOL(bestcomm_sram_alloc); -+EXPORT_SYMBOL(bestcomm_sram_free); -diff --git a/arch/powerpc/platforms/efika/mpc52xx_bestcomm_helper.c b/arch/powerpc/platforms/efika/mpc52xx_bestcomm_helper.c -new file mode 100644 -index 0000000..0eef3be ---- /dev/null -+++ b/arch/powerpc/platforms/efika/mpc52xx_bestcomm_helper.c -@@ -0,0 +1,299 @@ -+/* -+ * arch/powerpc/platforms/mpc52xx_bestcomm_helper.c -+ * -+ * This piece of code help the driver using the Bestcomm DMA -+ * for example, it find and setup the bestcomm dma tasks. -+ * Notice that the prototypes are all gather in Bestcomm.h -+ * -+ * 2006 (c) bplan GmbH 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. -+ * -+ */ -+ -+#undef DEBUG -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "bestcomm.h" -+ -+ -+/**************/ -+/**************/ -+/**************/ -+extern struct bestcomm_mainhandle bestcomm_mainhandle; -+ -+static int irqhack(int irq) -+{ -+ struct irq_host *mpc52xx_irqhost; -+ struct device_node *pic_dev; -+ -+ pic_dev = of_find_compatible_node(NULL, "interrupt-controller", "mpc5200-pic"); -+ -+ if (pic_dev == NULL) -+ return -1; -+ -+ mpc52xx_irqhost = irq_find_host(pic_dev); -+ if (mpc52xx_irqhost == NULL) -+ return -1; -+ -+ pr_debug("%s: irq=0x%x\n", __func__, irq); -+ return irq_create_mapping(mpc52xx_irqhost, irq); -+} -+ -+ -+/**************/ -+/**************/ -+/**************/ -+static struct sdma * -+sdma_task_preinit(char * devicetype, char * devicecomp, char* taskname, int bdnum) -+{ -+ struct sdma *sdma; -+ struct device_node *onenode; -+ struct device_node *parentnode; -+ uint32_t *oneptr; -+ int tasknum; -+ int irq; -+ -+ pr_debug("%s:\n", __FUNCTION__); -+ -+ if (!devicecomp) -+ return NULL; -+ -+ if (!taskname) -+ return NULL; -+ -+ if ( bestcomm_init_once() != 0) -+ return NULL; -+ -+ pr_debug("devicecomp=%s, taskname=%s, type=%s\n", devicecomp, taskname, devicetype); -+ -+ onenode = of_find_compatible_node(NULL, devicetype, devicecomp); -+ if (!onenode) -+ return NULL; -+ -+ pr_debug("node=%p\n", onenode); -+ -+ parentnode = onenode; -+ onenode = NULL; -+ while( (onenode = of_get_next_child(parentnode, onenode) ) ) -+ { -+ pr_debug("node=%p, name=%s\n", onenode, onenode->name); -+ if ( strcmp(onenode->name, taskname) == 0) -+ break; -+ } -+ -+ pr_debug("node=%p\n", onenode); -+ -+ if (!onenode) -+ return NULL; -+ -+ oneptr = (uint32_t*) get_property(onenode, "taskid", NULL); -+ if (!oneptr) -+ return NULL; -+ -+ tasknum = (int) * oneptr; -+ -+ pr_debug("tasknum=%d, bdnum=%d\n", tasknum, bdnum); -+ -+ sdma = (struct sdma *) bestcomm_taskallocate(tasknum, bdnum); -+ if (!sdma) -+ return NULL; -+ -+ irq = irq_of_parse_and_map(onenode, 0); -+ irqhack(irq); -+ -+ return sdma; -+} -+ -+ -+/**************/ -+/**************/ -+/**************/ -+/* -+ * FEC driver helper -+*/ -+ -+struct sdma * -+sdma_fex_tx_preinit(int bdnum) -+{ -+ pr_debug("\n"); -+ return sdma_task_preinit("network", "mpc5200-ethernet", "bestcomm-txtask", bdnum); -+} -+ -+int -+sdma_fec_tx_init(struct sdma *s, phys_addr_t fifo) -+{ -+ struct bestcomm_taskhandle *mytaskhandle = (struct bestcomm_taskhandle *) s; -+ struct sdma_fec_tx_var *var; -+ struct sdma_fec_tx_inc *inc; -+ -+ int tasknum = -1; -+ struct sdma_bd *bd = 0; -+ u32 bd_pa; -+ -+ if (!bd) -+ bd = (struct sdma_bd *)sdma_sram_alloc(sizeof(*bd) * mytaskhandle->num_bd, SDMA_BD_ALIGN, &bd_pa); -+ if (!bd) -+ return -ENOMEM; -+ -+ bestcomm_taskdisable(mytaskhandle); -+ -+ tasknum = mytaskhandle->taskid; -+ -+ mytaskhandle->bd = bd; -+ mytaskhandle->flags = SDMA_FLAGS_ENABLE_TASK; -+ mytaskhandle->index = 0; -+ mytaskhandle->outdex = 0; -+ memset(bd, 0, sizeof(*bd) * mytaskhandle->num_bd); -+ -+ var = (struct sdma_fec_tx_var *) bestcomm_taskget_vartable(mytaskhandle); -+ var->DRD = sdma_sram_pa( bestcomm_taskget_code(mytaskhandle) + 31); -+ var->fifo = fifo; -+ var->enable = sdma_io_pa(&bestcomm_mainhandle.sdma_io_basevirt->tcr[tasknum]); -+ var->bd_base = bd_pa; -+ var->bd_last = bd_pa + (mytaskhandle->num_bd - 1)*sizeof(struct sdma_bd); -+ var->bd_start = bd_pa; -+ -+ /* These are constants, they should have been in the image file */ -+ inc = (struct sdma_fec_tx_inc *)bestcomm_taskget_inctable(mytaskhandle); -+ inc->incr_bytes = -(s16)sizeof(u32); -+ inc->incr_src = sizeof(u32); -+ inc->incr_src_ma = sizeof(u8); -+ -+ pr_debug("tasknum=%d, bdnum=%d\n", tasknum, mytaskhandle->num_bd); -+ -+ mb(); -+ -+ return tasknum; -+} -+ -+struct sdma *sdma_fex_rx_preinit(int bdnum) -+{ -+ pr_debug("%s:\n", __FUNCTION__); -+ return sdma_task_preinit("network", "mpc5200-ethernet", "bestcomm-rxtask", bdnum); -+} -+ -+ -+int sdma_fec_rx_init(struct sdma *s, phys_addr_t fifo, int maxbufsize) -+{ -+ int tasknum; -+ struct sdma_fec_rx_var *var; -+ struct sdma_fec_rx_inc *inc; -+ struct bestcomm_taskhandle *mytaskhandle = (struct bestcomm_taskhandle *) s; -+ -+ struct sdma_bd *bd = 0; -+ u32 bd_pa; -+ -+ if (!bd) -+ bd = (struct sdma_bd *)sdma_sram_alloc(sizeof(*bd) * mytaskhandle->num_bd, SDMA_BD_ALIGN, &bd_pa); -+ -+ if (!bd) -+ return -ENOMEM; -+ -+ bestcomm_taskdisable(mytaskhandle); -+ -+ tasknum = mytaskhandle->taskid; -+ -+ mytaskhandle->bd = bd; -+ mytaskhandle->flags = SDMA_FLAGS_NONE; -+ mytaskhandle->index = 0; -+ mytaskhandle->outdex = 0; -+ memset(bd, 0, sizeof(*bd) * mytaskhandle->num_bd); -+ -+ var = (struct sdma_fec_rx_var *) bestcomm_taskget_vartable(mytaskhandle); -+ -+ var->enable = sdma_io_pa(&bestcomm_mainhandle.sdma_io_basevirt->tcr[tasknum]); -+ var->fifo = fifo; -+ var->bd_base = bd_pa; -+ var->bd_last = bd_pa + (mytaskhandle->num_bd - 1)*sizeof(struct sdma_bd); -+ var->bd_start = bd_pa; -+ var->buffer_size = maxbufsize; -+ -+ /* These are constants, they should have been in the image file */ -+ inc = (struct sdma_fec_rx_inc *) bestcomm_taskget_inctable(mytaskhandle); -+ inc->incr_bytes = -(s16)sizeof(u32); -+ inc->incr_dst = sizeof(u32); -+ inc->incr_dst_ma = sizeof(u8); -+ -+ pr_debug("tasknum=%d, bdnum=%d\n", tasknum, mytaskhandle->num_bd); -+ -+ mb(); -+ -+ return tasknum; -+} -+ -+/**************/ -+/**************/ -+/**************/ -+int sdma_ata_init(struct bestcomm_taskhandle *mytaskhandle, int maxbufsize) -+{ -+ struct sdma_ata_var *var; -+ struct sdma_bd2 *bd2 = 0; -+ u32 bd_pa; -+ int tasknum = -1; -+ -+ pr_debug("MyTaskHandle=%pn max buf=%d\n", mytaskhandle, maxbufsize); -+ -+ if (!bd2) -+ bd2 = (struct sdma_bd2 *)sdma_sram_alloc(sizeof(*bd2) * mytaskhandle->num_bd, SDMA_BD_ALIGN, &bd_pa); -+ -+ if (!bd2) -+ return -ENOMEM; -+ -+ bestcomm_taskdisable(mytaskhandle); -+ -+ tasknum = mytaskhandle->taskid; -+ -+ mytaskhandle->flags = SDMA_FLAGS_BD2; -+ mytaskhandle->bd2 = bd2; -+ mytaskhandle->index = 0; -+ mytaskhandle->outdex = 0; -+ memset(bd2, 0, sizeof(*bd2) * mytaskhandle->num_bd); -+ -+ var = (struct sdma_ata_var *)bestcomm_taskget_vartable(mytaskhandle); -+ var->enable = sdma_io_pa(&bestcomm_mainhandle.sdma_io_basevirt->tcr[tasknum]); -+ var->bd_base = bd_pa; -+ var->bd_last = bd_pa + (mytaskhandle->num_bd - 1)*sizeof(struct sdma_bd2); -+ var->bd_start = bd_pa; -+ var->buffer_size = maxbufsize; -+ -+ mb(); -+ -+ return 0; -+} -+ -+/**************/ -+ -+struct sdma *sdma_ata_preinit(int maxbuffers) -+{ -+ pr_debug("%s:\n", __FUNCTION__); -+ return sdma_task_preinit("ata", "mpc5200-ata", "bestcomm-task", maxbuffers); -+} -+ -+ -+/**************/ -+/* -+ * Export symbol for modules -+*/ -+ -+EXPORT_SYMBOL(sdma_sram_pa); -+EXPORT_SYMBOL(sdma_sram_va); -+EXPORT_SYMBOL(sdma_io_pa); -+EXPORT_SYMBOL(sdma_io_va); -+ -+EXPORT_SYMBOL(sdma_fex_tx_preinit); -+EXPORT_SYMBOL(sdma_fex_rx_preinit); -+EXPORT_SYMBOL(sdma_fec_rx_init); -+EXPORT_SYMBOL(sdma_fec_tx_init); -+ -+EXPORT_SYMBOL(sdma_ata_preinit); -+EXPORT_SYMBOL(sdma_ata_init); -diff --git a/arch/powerpc/platforms/efika/pci.c b/arch/powerpc/platforms/efika/pci.c -new file mode 100644 -index 0000000..62e05b2 ---- /dev/null -+++ b/arch/powerpc/platforms/efika/pci.c -@@ -0,0 +1,119 @@ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "efika.h" -+ -+#ifdef CONFIG_PCI -+/* -+ * Access functions for PCI config space using RTAS calls. -+ */ -+static int rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset, -+ int len, u32 * val) -+{ -+ struct pci_controller *hose = bus->sysdata; -+ unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) -+ | (((bus->number - hose->first_busno) & 0xff) << 16) -+ | (hose->index << 24); -+ int ret = -1; -+ int rval; -+ -+ rval = rtas_call(rtas_token("read-pci-config"), 2, 2, &ret, addr, len); -+ *val = ret; -+ return rval ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; -+} -+ -+static int rtas_write_config(struct pci_bus *bus, unsigned int devfn, -+ int offset, int len, u32 val) -+{ -+ struct pci_controller *hose = bus->sysdata; -+ unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) -+ | (((bus->number - hose->first_busno) & 0xff) << 16) -+ | (hose->index << 24); -+ int rval; -+ -+ rval = rtas_call(rtas_token("write-pci-config"), 3, 1, NULL, -+ addr, len, val); -+ return rval ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; -+} -+ -+static struct pci_ops rtas_pci_ops = { -+ rtas_read_config, -+ rtas_write_config -+}; -+ -+void __init efika_pcisetup(void) -+{ -+ const int *bus_range; -+ int len; -+ struct pci_controller *hose; -+ struct device_node *root; -+ struct device_node *pcictrl; -+ -+ root = of_find_node_by_path("/"); -+ if (root == NULL) { -+ printk(KERN_WARNING EFIKA_PLATFORM_NAME -+ ": Unable to find the root node\n"); -+ return; -+ } -+ -+ for (pcictrl = NULL;;) { -+ pcictrl = of_get_next_child(root, pcictrl); -+ if ((pcictrl == NULL) || (strcmp(pcictrl->name, "pci") == 0)) -+ break; -+ } -+ -+ of_node_put(root); -+ -+ if (pcictrl == NULL) { -+ printk(KERN_WARNING EFIKA_PLATFORM_NAME -+ ": Unable to find the PCI bridge node\n"); -+ return; -+ } -+ -+ bus_range = get_property(pcictrl, "bus-range", &len); -+ if (bus_range == NULL || len < 2 * sizeof(int)) { -+ printk(KERN_WARNING EFIKA_PLATFORM_NAME -+ ": Can't get bus-range for %s\n", pcictrl->full_name); -+ return; -+ } -+ -+ if (bus_range[1] == bus_range[0]) -+ printk(KERN_INFO EFIKA_PLATFORM_NAME ": PCI bus %d", -+ bus_range[0]); -+ else -+ printk(KERN_INFO EFIKA_PLATFORM_NAME ": PCI buses %d..%d", -+ bus_range[0], bus_range[1]); -+ printk(" controlled by %s\n", pcictrl->full_name); -+ printk("\n"); -+ -+ hose = pcibios_alloc_controller(); -+ if (!hose) { -+ printk(KERN_WARNING EFIKA_PLATFORM_NAME -+ ": Can't allocate PCI controller structure for %s\n", -+ pcictrl->full_name); -+ return; -+ } -+ -+ hose->arch_data = of_node_get(pcictrl); -+ hose->first_busno = bus_range[0]; -+ hose->last_busno = bus_range[1]; -+ hose->ops = &rtas_pci_ops; -+ -+ pci_process_bridge_OF_ranges(hose, pcictrl, 0); -+} -+ -+#else -+void __init efika_pcisetup(void) -+{} -+#endif -diff --git a/arch/powerpc/platforms/efika/setup.c b/arch/powerpc/platforms/efika/setup.c -new file mode 100644 -index 0000000..110c980 ---- /dev/null -+++ b/arch/powerpc/platforms/efika/setup.c -@@ -0,0 +1,150 @@ -+/* -+ * -+ * Efika 5K2 platform setup -+ * Some code really inspired from the lite5200b platform. -+ * -+ * Copyright (C) 2006 bplan GmbH -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "efika.h" -+ -+static void efika_show_cpuinfo(struct seq_file *m) -+{ -+ struct device_node *root; -+ const char *revision = NULL; -+ const char *codegendescription = NULL; -+ const char *codegenvendor = NULL; -+ -+ root = of_find_node_by_path("/"); -+ if (root) { -+ revision = get_property(root, "revision", NULL); -+ codegendescription = -+ get_property(root, "CODEGEN,description", NULL); -+ codegenvendor = get_property(root, "CODEGEN,vendor", NULL); -+ -+ of_node_put(root); -+ } -+ -+ if (codegendescription) -+ seq_printf(m, "machine\t\t: %s\n", codegendescription); -+ else -+ seq_printf(m, "machine\t\t: Efika\n"); -+ -+ if (revision) -+ seq_printf(m, "revision\t: %s\n", revision); -+ -+ if (codegenvendor) -+ seq_printf(m, "vendor\t\t: %s\n", codegenvendor); -+ -+ of_node_put(root); -+} -+ -+static void __init efika_setup_arch(void) -+{ -+ rtas_initialize(); -+ -+#ifdef CONFIG_BLK_DEV_INITRD -+ initrd_below_start_ok = 1; -+ -+ if (initrd_start) -+ ROOT_DEV = Root_RAM0; -+ else -+#endif -+ ROOT_DEV = Root_SDA2; /* sda2 (sda1 is for the kernel) */ -+ -+ efika_pcisetup(); -+ -+ if (ppc_md.progress) -+ ppc_md.progress("Linux/PPC " UTS_RELEASE " runnung on Efika ;-)\n", 0x0); -+} -+ -+static void __init efika_init(void) -+{ -+ struct device_node *np; -+ struct device_node *cnp = NULL; -+ const u32 *base; -+ -+ /* Find every child of the SOC node and add it to of_platform */ -+ np = of_find_node_by_name(NULL, "builtin"); -+ if (np) { -+ char name[BUS_ID_SIZE]; -+ while ((cnp = of_get_next_child(np, cnp))) { -+ strcpy(name, cnp->name); -+ -+ base = get_property(cnp, "reg", NULL); -+ if (base == NULL) -+ continue; -+ -+ snprintf(name+strlen(name), BUS_ID_SIZE, "@%x", *base); -+ of_platform_device_create(cnp, name, NULL); -+ -+ printk(KERN_INFO EFIKA_PLATFORM_NAME" : Added %s (type '%s' at '%s') to the known devices\n", name, cnp->type, cnp->full_name); -+ } -+ } -+ -+ if (ppc_md.progress) -+ ppc_md.progress(" Have fun with your Efika! ", 0x7777); -+} -+ -+static int __init efika_probe(void) -+{ -+ char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), -+ "model", NULL); -+ -+ if (model == NULL) -+ return 0; -+ if (strcmp(model, "EFIKA5K2")) -+ return 0; -+ -+ ISA_DMA_THRESHOLD = ~0L; -+ DMA_MODE_READ = 0x44; -+ DMA_MODE_WRITE = 0x48; -+ -+ return 1; -+} -+ -+define_machine(efika) -+{ -+ .name = EFIKA_PLATFORM_NAME, -+ .probe = efika_probe, -+ .setup_arch = efika_setup_arch, -+ .init = efika_init, -+ .show_cpuinfo = efika_show_cpuinfo, -+ .init_IRQ = mpc52xx_init_irq, -+ .get_irq = mpc52xx_get_irq, -+ .restart = rtas_restart, -+ .power_off = rtas_power_off, -+ .halt = rtas_halt, -+ .set_rtc_time = rtas_set_rtc_time, -+ .get_rtc_time = rtas_get_rtc_time, -+ .progress = rtas_progress, -+ .get_boot_time = rtas_get_boot_time, -+ .calibrate_decr = generic_calibrate_decr, -+ .phys_mem_access_prot = pci_phys_mem_access_prot, -+}; --- -1.4.3.2 - diff --git a/debian/patches/features/powerpc/efika/0004-Add-MPC5200-CPU-PIO-driver-using-libata.diff b/debian/patches/features/powerpc/efika/0010-libata-Add-support-for-the-MPC52xx-ATA-controller.txt similarity index 90% rename from debian/patches/features/powerpc/efika/0004-Add-MPC5200-CPU-PIO-driver-using-libata.diff rename to debian/patches/features/powerpc/efika/0010-libata-Add-support-for-the-MPC52xx-ATA-controller.txt index 8e8ef4ef1..4a69da5c2 100644 --- a/debian/patches/features/powerpc/efika/0004-Add-MPC5200-CPU-PIO-driver-using-libata.diff +++ b/debian/patches/features/powerpc/efika/0010-libata-Add-support-for-the-MPC52xx-ATA-controller.txt @@ -1,21 +1,24 @@ -From bb6dea9b9a251e42efcec030af2d5272d5d5714a Mon Sep 17 00:00:00 2001 -From: Nicolas DET -Date: Fri, 24 Nov 2006 13:01:30 +0100 -Subject: [PATCH] Add MPC5200 CPU/PIO driver using libata +From 83ebd6314e55f9baf2c4e795397346b338274ef5 Mon Sep 17 00:00:00 2001 +From: Sylvain Munaut +Date: Fri, 8 Dec 2006 00:08:14 +0100 +Subject: [PATCH] [PATCH] libata: Add support for the MPC52xx ATA controller -Signed-off-by: Nicolas DET +This patch adds initial libata support for the Freescale +MPC5200 integrated IDE controller. + +Signed-off-by: Sylvain Munaut +Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 9 + drivers/ata/Makefile | 1 + - drivers/ata/pata_mpc52xx.c | 510 ++++++++++++++++++++++++++++++++++++++++++++ - drivers/ata/pata_mpc52xx.h | 107 +++++++++ - 4 files changed, 627 insertions(+), 0 deletions(-) + drivers/ata/pata_mpc52xx.c | 563 ++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 573 insertions(+), 0 deletions(-) diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig -index 03f6338..be01ddf 100644 +index b34e0a9..fa1d327 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig -@@ -328,6 +328,15 @@ config PATA_TRIFLEX +@@ -337,6 +337,15 @@ config PATA_MARVELL If unsure, say N. @@ -32,23 +35,23 @@ index 03f6338..be01ddf 100644 tristate "Intel PATA MPIIX support" depends on PCI diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile -index 72243a6..e3a741c 100644 +index bc3d81a..3081e1f 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile -@@ -38,6 +38,7 @@ obj-$(CONFIG_PATA_NETCELL) += pata_netce +@@ -38,6 +38,7 @@ obj-$(CONFIG_PATA_NETCELL) += pata_netcell.o obj-$(CONFIG_PATA_NS87410) += pata_ns87410.o obj-$(CONFIG_PATA_OPTI) += pata_opti.o obj-$(CONFIG_PATA_OPTIDMA) += pata_optidma.o +obj-$(CONFIG_PATA_MPC52xx) += pata_mpc52xx.o + obj-$(CONFIG_PATA_MARVELL) += pata_marvell.o obj-$(CONFIG_PATA_MPIIX) += pata_mpiix.o obj-$(CONFIG_PATA_OLDPIIX) += pata_oldpiix.o - obj-$(CONFIG_PATA_PCMCIA) += pata_pcmcia.o diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c new file mode 100644 -index 0000000..c75d4c9 +index 0000000..8b7019a --- /dev/null +++ b/drivers/ata/pata_mpc52xx.c -@@ -0,0 +1,510 @@ +@@ -0,0 +1,563 @@ +/* + * drivers/ata/pata_mpc52xx.c + * @@ -65,15 +68,15 @@ index 0000000..c75d4c9 +#include +#include +#include ++#include +#include + +#include ++#include +#include +#include +#include + -+#include "pata_mpc52xx.h" -+ + +#define DRV_NAME "mpc52xx_ata" +#define DRV_VERSION "0.1.0" @@ -106,38 +109,91 @@ index 0000000..c75d4c9 +#define CALC_CLKCYC(c,v) ((((v)+(c)-1)/(c))) + + ++/* Bit definitions inside the registers */ ++#define MPC52xx_ATA_HOSTCONF_SMR 0x80000000UL /* State machine reset */ ++#define MPC52xx_ATA_HOSTCONF_FR 0x40000000UL /* FIFO Reset */ ++#define MPC52xx_ATA_HOSTCONF_IE 0x02000000UL /* Enable interrupt in PIO */ ++#define MPC52xx_ATA_HOSTCONF_IORDY 0x01000000UL /* Drive supports IORDY protocol */ ++ ++#define MPC52xx_ATA_HOSTSTAT_TIP 0x80000000UL /* Transaction in progress */ ++#define MPC52xx_ATA_HOSTSTAT_UREP 0x40000000UL /* UDMA Read Extended Pause */ ++#define MPC52xx_ATA_HOSTSTAT_RERR 0x02000000UL /* Read Error */ ++#define MPC52xx_ATA_HOSTSTAT_WERR 0x01000000UL /* Write Error */ ++ ++#define MPC52xx_ATA_FIFOSTAT_EMPTY 0x01 /* FIFO Empty */ ++ ++#define MPC52xx_ATA_DMAMODE_WRITE 0x01 /* Write DMA */ ++#define MPC52xx_ATA_DMAMODE_READ 0x02 /* Read DMA */ ++#define MPC52xx_ATA_DMAMODE_UDMA 0x04 /* UDMA enabled */ ++#define MPC52xx_ATA_DMAMODE_IE 0x08 /* Enable drive interrupt to CPU in DMA mode */ ++#define MPC52xx_ATA_DMAMODE_FE 0x10 /* FIFO Flush enable in Rx mode */ ++#define MPC52xx_ATA_DMAMODE_FR 0x20 /* FIFO Reset */ ++#define MPC52xx_ATA_DMAMODE_HUT 0x40 /* Host UDMA burst terminate */ ++ ++ ++/* Structure of the hardware registers */ ++struct mpc52xx_ata { ++ ++ /* Host interface registers */ ++ u32 config; /* ATA + 0x00 Host configuration */ ++ u32 host_status; /* ATA + 0x04 Host controller status */ ++ u32 pio1; /* ATA + 0x08 PIO Timing 1 */ ++ u32 pio2; /* ATA + 0x0c PIO Timing 2 */ ++ u32 mdma1; /* ATA + 0x10 MDMA Timing 1 */ ++ u32 mdma2; /* ATA + 0x14 MDMA Timing 2 */ ++ u32 udma1; /* ATA + 0x18 UDMA Timing 1 */ ++ u32 udma2; /* ATA + 0x1c UDMA Timing 2 */ ++ u32 udma3; /* ATA + 0x20 UDMA Timing 3 */ ++ u32 udma4; /* ATA + 0x24 UDMA Timing 4 */ ++ u32 udma5; /* ATA + 0x28 UDMA Timing 5 */ ++ u32 share_cnt; /* ATA + 0x2c ATA share counter */ ++ u32 reserved0[3]; ++ ++ /* FIFO registers */ ++ u32 fifo_data; /* ATA + 0x3c */ ++ u8 fifo_status_frame; /* ATA + 0x40 */ ++ u8 fifo_status; /* ATA + 0x41 */ ++ u16 reserved7[1]; ++ u8 fifo_control; /* ATA + 0x44 */ ++ u8 reserved8[5]; ++ u16 fifo_alarm; /* ATA + 0x4a */ ++ u16 reserved9; ++ u16 fifo_rdp; /* ATA + 0x4e */ ++ u16 reserved10; ++ u16 fifo_wrp; /* ATA + 0x52 */ ++ u16 reserved11; ++ u16 fifo_lfrdp; /* ATA + 0x56 */ ++ u16 reserved12; ++ u16 fifo_lfwrp; /* ATA + 0x5a */ ++ ++ /* Drive TaskFile registers */ ++ u8 tf_control; /* ATA + 0x5c TASKFILE Control/Alt Status */ ++ u8 reserved13[3]; ++ u16 tf_data; /* ATA + 0x60 TASKFILE Data */ ++ u16 reserved14; ++ u8 tf_features; /* ATA + 0x64 TASKFILE Features/Error */ ++ u8 reserved15[3]; ++ u8 tf_sec_count; /* ATA + 0x68 TASKFILE Sector Count */ ++ u8 reserved16[3]; ++ u8 tf_sec_num; /* ATA + 0x6c TASKFILE Sector Number */ ++ u8 reserved17[3]; ++ u8 tf_cyl_low; /* ATA + 0x70 TASKFILE Cylinder Low */ ++ u8 reserved18[3]; ++ u8 tf_cyl_high; /* ATA + 0x74 TASKFILE Cylinder High */ ++ u8 reserved19[3]; ++ u8 tf_dev_head; /* ATA + 0x78 TASKFILE Device/Head */ ++ u8 reserved20[3]; ++ u8 tf_command; /* ATA + 0x7c TASKFILE Command/Status */ ++ u8 dma_mode; /* ATA + 0x7d ATA Host DMA Mode configuration */ ++ u8 reserved21[2]; ++}; ++ ++ +/* ======================================================================== */ +/* Aux fns */ +/* ======================================================================== */ + + -+/* OF device tree */ -+ -+static unsigned int -+mpc52xx_find_ipb_freq(struct device_node *on) -+{ -+ struct device_node *onp; -+ const unsigned int *p_ipb_freq = NULL; -+ -+ of_node_get(on); -+ while (on) { -+ p_ipb_freq = get_property(on, "bus-frequency", NULL); -+ -+ if (p_ipb_freq) -+ break; -+ -+ onp = of_get_parent(on); -+ of_node_put(on); -+ on = onp; -+ } -+ -+ if (on) -+ of_node_put(on); -+ -+ return p_ipb_freq ? *p_ipb_freq : 0; -+} -+ -+ +/* MPC52xx low level hw control */ + +static int @@ -559,119 +615,6 @@ index 0000000..c75d4c9 +MODULE_DEVICE_TABLE(of, mpc52xx_ata_of_match); +MODULE_VERSION(DRV_VERSION); + -diff --git a/drivers/ata/pata_mpc52xx.h b/drivers/ata/pata_mpc52xx.h -new file mode 100644 -index 0000000..2430ae2 ---- /dev/null -+++ b/drivers/ata/pata_mpc52xx.h -@@ -0,0 +1,107 @@ -+/* -+ * drivers/ata/pata_mpc52xx.h -+ * -+ * Definitions for the Freescale MPC52xx on-chip IDE interface -+ * -+ * -+ * Copyright (C) 2006 Sylvain Munaut -+ * Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt -+ * -+ * 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. -+ */ -+ -+#ifndef __PATA_MPC52xx_H__ -+#define __PATA_MPC52xx_H__ -+ -+#include -+#include -+#include -+#include -+#include -+ -+ -+ -+/* Bit definitions inside the registers */ -+ -+#define MPC52xx_ATA_HOSTCONF_SMR 0x80000000UL /* State machine reset */ -+#define MPC52xx_ATA_HOSTCONF_FR 0x40000000UL /* FIFO Reset */ -+#define MPC52xx_ATA_HOSTCONF_IE 0x02000000UL /* Enable interrupt in PIO */ -+#define MPC52xx_ATA_HOSTCONF_IORDY 0x01000000UL /* Drive supports IORDY protocol */ -+ -+#define MPC52xx_ATA_HOSTSTAT_TIP 0x80000000UL /* Transaction in progress */ -+#define MPC52xx_ATA_HOSTSTAT_UREP 0x40000000UL /* UDMA Read Extended Pause */ -+#define MPC52xx_ATA_HOSTSTAT_RERR 0x02000000UL /* Read Error */ -+#define MPC52xx_ATA_HOSTSTAT_WERR 0x01000000UL /* Write Error */ -+ -+#define MPC52xx_ATA_FIFOSTAT_EMPTY 0x01 /* FIFO Empty */ -+ -+#define MPC52xx_ATA_DMAMODE_WRITE 0x01 /* Write DMA */ -+#define MPC52xx_ATA_DMAMODE_READ 0x02 /* Read DMA */ -+#define MPC52xx_ATA_DMAMODE_UDMA 0x04 /* UDMA enabled */ -+#define MPC52xx_ATA_DMAMODE_IE 0x08 /* Enable drive interrupt to CPU in DMA mode */ -+#define MPC52xx_ATA_DMAMODE_FE 0x10 /* FIFO Flush enable in Rx mode */ -+#define MPC52xx_ATA_DMAMODE_FR 0x20 /* FIFO Reset */ -+#define MPC52xx_ATA_DMAMODE_HUT 0x40 /* Host UDMA burst terminate */ -+ -+ -+/* Structure of the hardware registers */ -+struct mpc52xx_ata { -+ -+ /* Host interface registers */ -+ u32 config; /* ATA + 0x00 Host configuration */ -+ u32 host_status; /* ATA + 0x04 Host controller status */ -+ u32 pio1; /* ATA + 0x08 PIO Timing 1 */ -+ u32 pio2; /* ATA + 0x0c PIO Timing 2 */ -+ u32 mdma1; /* ATA + 0x10 MDMA Timing 1 */ -+ u32 mdma2; /* ATA + 0x14 MDMA Timing 2 */ -+ u32 udma1; /* ATA + 0x18 UDMA Timing 1 */ -+ u32 udma2; /* ATA + 0x1c UDMA Timing 2 */ -+ u32 udma3; /* ATA + 0x20 UDMA Timing 3 */ -+ u32 udma4; /* ATA + 0x24 UDMA Timing 4 */ -+ u32 udma5; /* ATA + 0x28 UDMA Timing 5 */ -+ u32 share_cnt; /* ATA + 0x2c ATA share counter */ -+ u32 reserved0[3]; -+ -+ /* FIFO registers */ -+ u32 fifo_data; /* ATA + 0x3c */ -+ u8 fifo_status_frame; /* ATA + 0x40 */ -+ u8 fifo_status; /* ATA + 0x41 */ -+ u16 reserved7[1]; -+ u8 fifo_control; /* ATA + 0x44 */ -+ u8 reserved8[5]; -+ u16 fifo_alarm; /* ATA + 0x4a */ -+ u16 reserved9; -+ u16 fifo_rdp; /* ATA + 0x4e */ -+ u16 reserved10; -+ u16 fifo_wrp; /* ATA + 0x52 */ -+ u16 reserved11; -+ u16 fifo_lfrdp; /* ATA + 0x56 */ -+ u16 reserved12; -+ u16 fifo_lfwrp; /* ATA + 0x5a */ -+ -+ /* Drive TaskFile registers */ -+ u8 tf_control; /* ATA + 0x5c TASKFILE Control/Alt Status */ -+ u8 reserved13[3]; -+ u16 tf_data; /* ATA + 0x60 TASKFILE Data */ -+ u16 reserved14; -+ u8 tf_features; /* ATA + 0x64 TASKFILE Features/Error */ -+ u8 reserved15[3]; -+ u8 tf_sec_count; /* ATA + 0x68 TASKFILE Sector Count */ -+ u8 reserved16[3]; -+ u8 tf_sec_num; /* ATA + 0x6c TASKFILE Sector Number */ -+ u8 reserved17[3]; -+ u8 tf_cyl_low; /* ATA + 0x70 TASKFILE Cylinder Low */ -+ u8 reserved18[3]; -+ u8 tf_cyl_high; /* ATA + 0x74 TASKFILE Cylinder High */ -+ u8 reserved19[3]; -+ u8 tf_dev_head; /* ATA + 0x78 TASKFILE Device/Head */ -+ u8 reserved20[3]; -+ u8 tf_command; /* ATA + 0x7c TASKFILE Command/Status */ -+ u8 dma_mode; /* ATA + 0x7d ATA Host DMA Mode configuration */ -+ u8 reserved21[2]; -+}; -+ -+#endif /* __PATA_MPC52xx_H__ */ -+ -- -1.4.3.2 +1.4.4.2 diff --git a/debian/patches/features/powerpc/efika/0011-Filter-out-efika.diff b/debian/patches/features/powerpc/efika/0011-Filter-out-efika.diff deleted file mode 100644 index 29c1532b8..000000000 --- a/debian/patches/features/powerpc/efika/0011-Filter-out-efika.diff +++ /dev/null @@ -1,38 +0,0 @@ -From 473274f1f615316cf5828caa47704f4d2f9ad1be Mon Sep 17 00:00:00 2001 -From: Nicolas DET -Date: Fri, 24 Nov 2006 13:34:18 +0100 -Subject: [PATCH] Filter out efika - -Signed-off-by: Nicolas DET ---- - arch/powerpc/platforms/chrp/setup.c | 9 +++++++++ - 1 files changed, 9 insertions(+), 0 deletions(-) - -diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c -index 49b8dab..1337da8 100644 ---- a/arch/powerpc/platforms/chrp/setup.c -+++ b/arch/powerpc/platforms/chrp/setup.c -@@ -580,11 +580,20 @@ static int __init chrp_probe(void) - { - char *dtype = of_get_flat_dt_prop(of_get_flat_dt_root(), - "device_type", NULL); -+ -+ char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), -+ "model", NULL); - if (dtype == NULL) - return 0; - if (strcmp(dtype, "chrp")) - return 0; - -+ /* -+ * Filter out efika because it has its own platform -+ */ -+ if (model && (strcmp(model, "EFIKA5K2") == 0) ) -+ return 0; -+ - ISA_DMA_THRESHOLD = ~0L; - DMA_MODE_READ = 0x44; - DMA_MODE_WRITE = 0x48; --- -1.4.3.2 - diff --git a/debian/patches/features/powerpc/efika/0011-ohci-Whitespace-and-typo-fix-in-ohci-ppc-of.c.txt b/debian/patches/features/powerpc/efika/0011-ohci-Whitespace-and-typo-fix-in-ohci-ppc-of.c.txt new file mode 100644 index 000000000..2228fa06b --- /dev/null +++ b/debian/patches/features/powerpc/efika/0011-ohci-Whitespace-and-typo-fix-in-ohci-ppc-of.c.txt @@ -0,0 +1,38 @@ +From 947dc060772ceb8b33a35bd2ded245908fa9442f Mon Sep 17 00:00:00 2001 +From: Sylvain Munaut +Date: Sat, 23 Dec 2006 22:16:05 +0100 +Subject: [PATCH] [PATCH] ohci: Whitespace and typo fix in ohci-ppc-of.c + +Signed-off-by: Sylvain Munaut +--- + drivers/usb/host/ohci-ppc-of.c | 6 +++--- + 1 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c +index 84b555b..08e237c 100644 +--- a/drivers/usb/host/ohci-ppc-of.c ++++ b/drivers/usb/host/ohci-ppc-of.c +@@ -96,9 +96,9 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match) + if (usb_disabled()) + return -ENODEV; + +- is_bigendian = ++ is_bigendian = + device_is_compatible(dn, "ohci-bigendian") || +- device_is_compatible(dn, "ohci-be");; ++ device_is_compatible(dn, "ohci-be"); + + dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n"); + +@@ -206,7 +206,7 @@ static struct of_device_id ohci_hcd_ppc_of_match[] = { + #endif + {}, + }; +-MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match); ++MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match); + + #if !defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \ + !defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE) +-- +1.4.4.2 + diff --git a/debian/patches/features/powerpc/efika/0012-Backport-of_platform.diff b/debian/patches/features/powerpc/efika/0012-Backport-of_platform.diff deleted file mode 100644 index 4ec17e761..000000000 --- a/debian/patches/features/powerpc/efika/0012-Backport-of_platform.diff +++ /dev/null @@ -1,900 +0,0 @@ -From 2842fd40de284f328016997ba40d7b83823510c5 Mon Sep 17 00:00:00 2001 -From: Nicolas DET -Date: Fri, 24 Nov 2006 13:49:57 +0100 -Subject: [PATCH] Backport of_platform - -Signed-off-by: Nicolas DET ---- - arch/powerpc/kernel/Makefile | 2 +- - arch/powerpc/kernel/of_device.c | 172 +++------------ - arch/powerpc/kernel/of_platform.c | 374 +++++++++++++++++++++++++++++++ - arch/powerpc/platforms/powermac/setup.c | 1 + - drivers/macintosh/smu.c | 3 +- - drivers/macintosh/therm_adt746x.c | 2 +- - drivers/macintosh/therm_pm72.c | 5 +- - drivers/macintosh/therm_windtunnel.c | 7 +- - drivers/video/platinumfb.c | 5 +- - include/asm-powerpc/of_device.h | 34 +--- - include/asm-powerpc/of_platform.h | 60 +++++ - 11 files changed, 478 insertions(+), 187 deletions(-) - -diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile -index 7af23c4..6d9476f 100644 ---- a/arch/powerpc/kernel/Makefile -+++ b/arch/powerpc/kernel/Makefile -@@ -21,7 +21,7 @@ obj-$(CONFIG_PPC64) += setup_64.o binfm - obj-$(CONFIG_PPC64) += vdso64/ - obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o - obj-$(CONFIG_PPC_970_NAP) += idle_power4.o --obj-$(CONFIG_PPC_OF) += of_device.o prom_parse.o -+obj-$(CONFIG_PPC_OF) += of_device.o of_platform.o prom_parse.o - procfs-$(CONFIG_PPC64) := proc_ppc64.o - obj-$(CONFIG_PROC_FS) += $(procfs-y) - rtaspci-$(CONFIG_PPC64) := rtas_pci.o -diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c -index 397c83e..5c65398 100644 ---- a/arch/powerpc/kernel/of_device.c -+++ b/arch/powerpc/kernel/of_device.c -@@ -9,30 +9,26 @@ #include - #include - - /** -- * of_match_device - Tell if an of_device structure has a matching -- * of_match structure -+ * of_match_node - Tell if an device_node has a matching of_match structure - * @ids: array of of device match structures to search in -- * @dev: the of device structure to match against -+ * @node: the of device structure to match against - * -- * Used by a driver to check whether an of_device present in the -- * system is in its list of supported devices. -+ * Low level utility function used by device matching. - */ --const struct of_device_id *of_match_device(const struct of_device_id *matches, -- const struct of_device *dev) -+const struct of_device_id *of_match_node(const struct of_device_id *matches, -+ const struct device_node *node) - { -- if (!dev->node) -- return NULL; - while (matches->name[0] || matches->type[0] || matches->compatible[0]) { - int match = 1; - if (matches->name[0]) -- match &= dev->node->name -- && !strcmp(matches->name, dev->node->name); -+ match &= node->name -+ && !strcmp(matches->name, node->name); - if (matches->type[0]) -- match &= dev->node->type -- && !strcmp(matches->type, dev->node->type); -+ match &= node->type -+ && !strcmp(matches->type, node->type); - if (matches->compatible[0]) -- match &= device_is_compatible(dev->node, -- matches->compatible); -+ match &= device_is_compatible(node, -+ matches->compatible); - if (match) - return matches; - matches++; -@@ -40,16 +36,21 @@ const struct of_device_id *of_match_devi - return NULL; - } - --static int of_platform_bus_match(struct device *dev, struct device_driver *drv) -+/** -+ * of_match_device - Tell if an of_device structure has a matching -+ * of_match structure -+ * @ids: array of of device match structures to search in -+ * @dev: the of device structure to match against -+ * -+ * Used by a driver to check whether an of_device present in the -+ * system is in its list of supported devices. -+ */ -+const struct of_device_id *of_match_device(const struct of_device_id *matches, -+ const struct of_device *dev) - { -- struct of_device * of_dev = to_of_device(dev); -- struct of_platform_driver * of_drv = to_of_platform_driver(drv); -- const struct of_device_id * matches = of_drv->match_table; -- -- if (!matches) -- return 0; -- -- return of_match_device(matches, of_dev) != NULL; -+ if (!dev->node) -+ return NULL; -+ return of_match_node(matches, dev->node); - } - - struct of_device *of_dev_get(struct of_device *dev) -@@ -71,96 +72,8 @@ void of_dev_put(struct of_device *dev) - put_device(&dev->dev); - } - -- --static int of_device_probe(struct device *dev) --{ -- int error = -ENODEV; -- struct of_platform_driver *drv; -- struct of_device *of_dev; -- const struct of_device_id *match; -- -- drv = to_of_platform_driver(dev->driver); -- of_dev = to_of_device(dev); -- -- if (!drv->probe) -- return error; -- -- of_dev_get(of_dev); -- -- match = of_match_device(drv->match_table, of_dev); -- if (match) -- error = drv->probe(of_dev, match); -- if (error) -- of_dev_put(of_dev); -- -- return error; --} -- --static int of_device_remove(struct device *dev) --{ -- struct of_device * of_dev = to_of_device(dev); -- struct of_platform_driver * drv = to_of_platform_driver(dev->driver); -- -- if (dev->driver && drv->remove) -- drv->remove(of_dev); -- return 0; --} -- --static int of_device_suspend(struct device *dev, pm_message_t state) --{ -- struct of_device * of_dev = to_of_device(dev); -- struct of_platform_driver * drv = to_of_platform_driver(dev->driver); -- int error = 0; -- -- if (dev->driver && drv->suspend) -- error = drv->suspend(of_dev, state); -- return error; --} -- --static int of_device_resume(struct device * dev) --{ -- struct of_device * of_dev = to_of_device(dev); -- struct of_platform_driver * drv = to_of_platform_driver(dev->driver); -- int error = 0; -- -- if (dev->driver && drv->resume) -- error = drv->resume(of_dev); -- return error; --} -- --struct bus_type of_platform_bus_type = { -- .name = "of_platform", -- .match = of_platform_bus_match, -- .probe = of_device_probe, -- .remove = of_device_remove, -- .suspend = of_device_suspend, -- .resume = of_device_resume, --}; -- --static int __init of_bus_driver_init(void) --{ -- return bus_register(&of_platform_bus_type); --} -- --postcore_initcall(of_bus_driver_init); -- --int of_register_driver(struct of_platform_driver *drv) --{ -- /* initialize common driver fields */ -- drv->driver.name = drv->name; -- drv->driver.bus = &of_platform_bus_type; -- -- /* register with core */ -- return driver_register(&drv->driver); --} -- --void of_unregister_driver(struct of_platform_driver *drv) --{ -- driver_unregister(&drv->driver); --} -- -- --static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf) -+static ssize_t dev_show_devspec(struct device *dev, -+ struct device_attribute *attr, char *buf) - { - struct of_device *ofdev; - -@@ -208,41 +121,10 @@ void of_device_unregister(struct of_devi - device_unregister(&ofdev->dev); - } - --struct of_device* of_platform_device_create(struct device_node *np, -- const char *bus_id, -- struct device *parent) --{ -- struct of_device *dev; -- -- dev = kmalloc(sizeof(*dev), GFP_KERNEL); -- if (!dev) -- return NULL; -- memset(dev, 0, sizeof(*dev)); -- -- dev->node = of_node_get(np); -- dev->dma_mask = 0xffffffffUL; -- dev->dev.dma_mask = &dev->dma_mask; -- dev->dev.parent = parent; -- dev->dev.bus = &of_platform_bus_type; -- dev->dev.release = of_release_dev; -- -- strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE); -- -- if (of_device_register(dev) != 0) { -- kfree(dev); -- return NULL; -- } -- -- return dev; --} - - EXPORT_SYMBOL(of_match_device); --EXPORT_SYMBOL(of_platform_bus_type); --EXPORT_SYMBOL(of_register_driver); --EXPORT_SYMBOL(of_unregister_driver); - EXPORT_SYMBOL(of_device_register); - EXPORT_SYMBOL(of_device_unregister); - EXPORT_SYMBOL(of_dev_get); - EXPORT_SYMBOL(of_dev_put); --EXPORT_SYMBOL(of_platform_device_create); - EXPORT_SYMBOL(of_release_dev); -diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c -new file mode 100644 -index 0000000..41c71bc ---- /dev/null -+++ b/arch/powerpc/kernel/of_platform.c -@@ -0,0 +1,374 @@ -+/* -+ * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp. -+ * -+ * -+ * 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. -+ * -+ */ -+ -+#undef DEBUG -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#ifdef CONFIG_PPC_DCR -+#include -+#endif -+#include -+#include -+ -+ -+/* -+ * The list of OF IDs below is used for matching bus types in the -+ * system whose devices are to be exposed as of_platform_devices. -+ * -+ * This is the default list valid for most platforms. This file provides -+ * functions who can take an explicit list if necessary though -+ * -+ * The search is always performed recursively looking for children of -+ * the provided device_node and recursively if such a children matches -+ * a bus type in the list -+ */ -+ -+static struct of_device_id of_default_bus_ids[] = { -+ { .type = "soc", }, -+ { .compatible = "soc", }, -+ { .type = "spider", }, -+ { .type = "axon", }, -+ { .type = "plb5", }, -+ { .type = "plb4", }, -+ { .type = "opb", }, -+ {}, -+}; -+ -+/* -+ * -+ * OF platform device type definition & base infrastructure -+ * -+ */ -+ -+static int of_platform_bus_match(struct device *dev, struct device_driver *drv) -+{ -+ struct of_device * of_dev = to_of_device(dev); -+ struct of_platform_driver * of_drv = to_of_platform_driver(drv); -+ const struct of_device_id * matches = of_drv->match_table; -+ -+ if (!matches) -+ return 0; -+ -+ return of_match_device(matches, of_dev) != NULL; -+} -+ -+static int of_platform_device_probe(struct device *dev) -+{ -+ int error = -ENODEV; -+ struct of_platform_driver *drv; -+ struct of_device *of_dev; -+ const struct of_device_id *match; -+ -+ drv = to_of_platform_driver(dev->driver); -+ of_dev = to_of_device(dev); -+ -+ if (!drv->probe) -+ return error; -+ -+ of_dev_get(of_dev); -+ -+ match = of_match_device(drv->match_table, of_dev); -+ if (match) -+ error = drv->probe(of_dev, match); -+ if (error) -+ of_dev_put(of_dev); -+ -+ return error; -+} -+ -+static int of_platform_device_remove(struct device *dev) -+{ -+ struct of_device * of_dev = to_of_device(dev); -+ struct of_platform_driver * drv = to_of_platform_driver(dev->driver); -+ -+ if (dev->driver && drv->remove) -+ drv->remove(of_dev); -+ return 0; -+} -+ -+static int of_platform_device_suspend(struct device *dev, pm_message_t state) -+{ -+ struct of_device * of_dev = to_of_device(dev); -+ struct of_platform_driver * drv = to_of_platform_driver(dev->driver); -+ int error = 0; -+ -+ if (dev->driver && drv->suspend) -+ error = drv->suspend(of_dev, state); -+ return error; -+} -+ -+static int of_platform_device_resume(struct device * dev) -+{ -+ struct of_device * of_dev = to_of_device(dev); -+ struct of_platform_driver * drv = to_of_platform_driver(dev->driver); -+ int error = 0; -+ -+ if (dev->driver && drv->resume) -+ error = drv->resume(of_dev); -+ return error; -+} -+ -+struct bus_type of_platform_bus_type = { -+ .name = "of_platform", -+ .match = of_platform_bus_match, -+ .probe = of_platform_device_probe, -+ .remove = of_platform_device_remove, -+ .suspend = of_platform_device_suspend, -+ .resume = of_platform_device_resume, -+}; -+EXPORT_SYMBOL(of_platform_bus_type); -+ -+static int __init of_bus_driver_init(void) -+{ -+ return bus_register(&of_platform_bus_type); -+} -+ -+postcore_initcall(of_bus_driver_init); -+ -+int of_register_platform_driver(struct of_platform_driver *drv) -+{ -+ /* initialize common driver fields */ -+ drv->driver.name = drv->name; -+ drv->driver.bus = &of_platform_bus_type; -+ -+ /* register with core */ -+ return driver_register(&drv->driver); -+} -+EXPORT_SYMBOL(of_register_platform_driver); -+ -+void of_unregister_platform_driver(struct of_platform_driver *drv) -+{ -+ driver_unregister(&drv->driver); -+} -+EXPORT_SYMBOL(of_unregister_platform_driver); -+ -+static void of_platform_make_bus_id(struct of_device *dev) -+{ -+ struct device_node *node = dev->node; -+ char *name = dev->dev.bus_id; -+ const u32 *reg; -+ u64 addr; -+ -+ /* -+ * If it's a DCR based device, use 'd' for native DCRs -+ * and 'D' for MMIO DCRs. -+ */ -+#ifdef CONFIG_PPC_DCR -+ reg = get_property(node, "dcr-reg", NULL); -+ if (reg) { -+#ifdef CONFIG_PPC_DCR_NATIVE -+ snprintf(name, BUS_ID_SIZE, "d%x.%s", -+ *reg, node->name); -+#else /* CONFIG_PPC_DCR_NATIVE */ -+ addr = of_translate_dcr_address(node, *reg, NULL); -+ if (addr != OF_BAD_ADDR) { -+ snprintf(name, BUS_ID_SIZE, -+ "D%llx.%s", (unsigned long long)addr, -+ node->name); -+ return; -+ } -+#endif /* !CONFIG_PPC_DCR_NATIVE */ -+ } -+#endif /* CONFIG_PPC_DCR */ -+ -+ /* -+ * For MMIO, get the physical address -+ */ -+ reg = get_property(node, "reg", NULL); -+ if (reg) { -+ addr = of_translate_address(node, reg); -+ if (addr != OF_BAD_ADDR) { -+ snprintf(name, BUS_ID_SIZE, -+ "%llx.%s", (unsigned long long)addr, -+ node->name); -+ return; -+ } -+ } -+ -+ /* -+ * No BusID, use the node name and pray -+ */ -+ snprintf(name, BUS_ID_SIZE, "%s", node->name); -+} -+ -+struct of_device* of_platform_device_create(struct device_node *np, -+ const char *bus_id, -+ struct device *parent) -+{ -+ struct of_device *dev; -+ -+ dev = kmalloc(sizeof(*dev), GFP_KERNEL); -+ if (!dev) -+ return NULL; -+ memset(dev, 0, sizeof(*dev)); -+ -+ dev->node = of_node_get(np); -+ dev->dma_mask = 0xffffffffUL; -+ dev->dev.dma_mask = &dev->dma_mask; -+ dev->dev.parent = parent; -+ dev->dev.bus = &of_platform_bus_type; -+ dev->dev.release = of_release_dev; -+ -+ if (bus_id) -+ strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE); -+ else -+ of_platform_make_bus_id(dev); -+ -+ if (of_device_register(dev) != 0) { -+ kfree(dev); -+ return NULL; -+ } -+ -+ return dev; -+} -+EXPORT_SYMBOL(of_platform_device_create); -+ -+ -+ -+/** -+ * of_platform_bus_create - Create an OF device for a bus node and all its -+ * children. Optionally recursively instanciate matching busses. -+ * @bus: device node of the bus to instanciate -+ * @matches: match table, NULL to use the default, OF_NO_DEEP_PROBE to -+ * disallow recursive creation of child busses -+ */ -+static int of_platform_bus_create(struct device_node *bus, -+ struct of_device_id *matches, -+ struct device *parent) -+{ -+ struct device_node *child; -+ struct of_device *dev; -+ int rc = 0; -+ -+ for (child = NULL; (child = of_get_next_child(bus, child)); ) { -+ pr_debug(" create child: %s\n", child->full_name); -+ dev = of_platform_device_create(child, NULL, parent); -+ if (dev == NULL) -+ rc = -ENOMEM; -+ else if (!of_match_node(matches, child)) -+ continue; -+ if (rc == 0) { -+ pr_debug(" and sub busses\n"); -+ rc = of_platform_bus_create(child, matches, &dev->dev); -+ } if (rc) { -+ of_node_put(child); -+ break; -+ } -+ } -+ return rc; -+} -+ -+/** -+ * of_platform_bus_probe - Probe the device-tree for platform busses -+ * @root: parent of the first level to probe or NULL for the root of the tree -+ * @matches: match table, NULL to use the default -+ * @parent: parent to hook devices from, NULL for toplevel -+ * -+ * Note that children of the provided root are not instanciated as devices -+ * unless the specified root itself matches the bus list and is not NULL. -+ */ -+ -+int of_platform_bus_probe(struct device_node *root, -+ struct of_device_id *matches, -+ struct device *parent) -+{ -+ struct device_node *child; -+ struct of_device *dev; -+ int rc = 0; -+ -+ if (matches == NULL) -+ matches = of_default_bus_ids; -+ if (matches == OF_NO_DEEP_PROBE) -+ return -EINVAL; -+ if (root == NULL) -+ root = of_find_node_by_path("/"); -+ else -+ of_node_get(root); -+ -+ pr_debug("of_platform_bus_probe()\n"); -+ pr_debug(" starting at: %s\n", root->full_name); -+ -+ /* Do a self check of bus type, if there's a match, create -+ * children -+ */ -+ if (of_match_node(matches, root)) { -+ pr_debug(" root match, create all sub devices\n"); -+ dev = of_platform_device_create(root, NULL, parent); -+ if (dev == NULL) { -+ rc = -ENOMEM; -+ goto bail; -+ } -+ pr_debug(" create all sub busses\n"); -+ rc = of_platform_bus_create(root, matches, &dev->dev); -+ goto bail; -+ } -+ for (child = NULL; (child = of_get_next_child(root, child)); ) { -+ if (!of_match_node(matches, child)) -+ continue; -+ -+ pr_debug(" match: %s\n", child->full_name); -+ dev = of_platform_device_create(child, NULL, parent); -+ if (dev == NULL) -+ rc = -ENOMEM; -+ else -+ rc = of_platform_bus_create(child, matches, &dev->dev); -+ if (rc) { -+ of_node_put(child); -+ break; -+ } -+ } -+ bail: -+ of_node_put(root); -+ return rc; -+} -+EXPORT_SYMBOL(of_platform_bus_probe); -+ -+static int of_dev_node_match(struct device *dev, void *data) -+{ -+ return to_of_device(dev)->node == data; -+} -+ -+struct of_device *of_find_device_by_node(struct device_node *np) -+{ -+ struct device *dev; -+ -+ dev = bus_find_device(&of_platform_bus_type, -+ NULL, np, of_dev_node_match); -+ if (dev) -+ return to_of_device(dev); -+ return NULL; -+} -+EXPORT_SYMBOL(of_find_device_by_node); -+ -+static int of_dev_phandle_match(struct device *dev, void *data) -+{ -+ phandle *ph = data; -+ return to_of_device(dev)->node->linux_phandle == *ph; -+} -+ -+struct of_device *of_find_device_by_phandle(phandle ph) -+{ -+ struct device *dev; -+ -+ dev = bus_find_device(&of_platform_bus_type, -+ NULL, &ph, of_dev_phandle_match); -+ if (dev) -+ return to_of_device(dev); -+ return NULL; -+} -+EXPORT_SYMBOL(of_find_device_by_phandle); -diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c -index 824a618..e25a0bd 100644 ---- a/arch/powerpc/platforms/powermac/setup.c -+++ b/arch/powerpc/platforms/powermac/setup.c -@@ -70,6 +70,7 @@ #include - #include - #include - #include -+#include - #include - #include - #include -diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c -index ade25b3..4f724cd 100644 ---- a/drivers/macintosh/smu.c -+++ b/drivers/macintosh/smu.c -@@ -46,6 +46,7 @@ #include - #include - #include - #include -+#include - - #define VERSION "0.7" - #define AUTHOR "(c) 2005 Benjamin Herrenschmidt, IBM Corp." -@@ -653,7 +654,7 @@ static int __init smu_init_sysfs(void) - * I'm a bit too far from figuring out how that works with those - * new chipsets, but that will come back and bite us - */ -- of_register_driver(&smu_of_platform_driver); -+ of_register_platform_driver(&smu_of_platform_driver); - return 0; - } - -diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c -index a0f30d0..13b953a 100644 ---- a/drivers/macintosh/therm_adt746x.c -+++ b/drivers/macintosh/therm_adt746x.c -@@ -30,7 +30,7 @@ #include - #include - #include - #include --#include -+#include - - #undef DEBUG - -diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c -index d00c0c3..2e4ad44 100644 ---- a/drivers/macintosh/therm_pm72.c -+++ b/drivers/macintosh/therm_pm72.c -@@ -129,6 +129,7 @@ #include - #include - #include - #include -+#include - - #include "therm_pm72.h" - -@@ -2236,14 +2237,14 @@ static int __init therm_pm72_init(void) - return -ENODEV; - } - -- of_register_driver(&fcu_of_platform_driver); -+ of_register_platform_driver(&fcu_of_platform_driver); - - return 0; - } - - static void __exit therm_pm72_exit(void) - { -- of_unregister_driver(&fcu_of_platform_driver); -+ of_unregister_platform_driver(&fcu_of_platform_driver); - - if (of_dev) - of_device_unregister(of_dev); -diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c -index 738faab..a1d3a98 100644 ---- a/drivers/macintosh/therm_windtunnel.c -+++ b/drivers/macintosh/therm_windtunnel.c -@@ -36,12 +36,13 @@ #include - #include - #include - #include -+ - #include - #include - #include - #include - #include --#include -+#include - #include - - #define LOG_TEMP 0 /* continously log temperature */ -@@ -511,14 +512,14 @@ g4fan_init( void ) - return -ENODEV; - } - -- of_register_driver( &therm_of_driver ); -+ of_register_platform_driver( &therm_of_driver ); - return 0; - } - - static void __exit - g4fan_exit( void ) - { -- of_unregister_driver( &therm_of_driver ); -+ of_unregister_platform_driver( &therm_of_driver ); - - if( x.of_dev ) - of_device_unregister( x.of_dev ); -diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c -index fdb33cd..cb26c6d 100644 ---- a/drivers/video/platinumfb.c -+++ b/drivers/video/platinumfb.c -@@ -34,6 +34,7 @@ #include - #include - #include - #include -+#include - - #include "macmodes.h" - #include "platinumfb.h" -@@ -682,14 +683,14 @@ #ifndef MODULE - return -ENODEV; - platinumfb_setup(option); - #endif -- of_register_driver(&platinum_driver); -+ of_register_platform_driver(&platinum_driver); - - return 0; - } - - static void __exit platinumfb_exit(void) - { -- of_unregister_driver(&platinum_driver); -+ of_unregister_platform_driver(&platinum_driver); - } - - MODULE_LICENSE("GPL"); -diff --git a/include/asm-powerpc/of_device.h b/include/asm-powerpc/of_device.h -index c5c0b0b..1ef7e9e 100644 ---- a/include/asm-powerpc/of_device.h -+++ b/include/asm-powerpc/of_device.h -@@ -6,12 +6,6 @@ #include - #include - #include - --/* -- * The of_platform_bus_type is a bus type used by drivers that do not -- * attach to a macio or similar bus but still use OF probing -- * mechanism -- */ --extern struct bus_type of_platform_bus_type; - - /* - * The of_device is a kind of "base class" that is a superset of -@@ -26,40 +20,16 @@ struct of_device - }; - #define to_of_device(d) container_of(d, struct of_device, dev) - -+extern const struct of_device_id *of_match_node( -+ const struct of_device_id *matches, const struct device_node *node); - extern const struct of_device_id *of_match_device( - const struct of_device_id *matches, const struct of_device *dev); - - extern struct of_device *of_dev_get(struct of_device *dev); - extern void of_dev_put(struct of_device *dev); - --/* -- * An of_platform_driver driver is attached to a basic of_device on -- * the "platform bus" (of_platform_bus_type) -- */ --struct of_platform_driver --{ -- char *name; -- struct of_device_id *match_table; -- struct module *owner; -- -- int (*probe)(struct of_device* dev, const struct of_device_id *match); -- int (*remove)(struct of_device* dev); -- -- int (*suspend)(struct of_device* dev, pm_message_t state); -- int (*resume)(struct of_device* dev); -- int (*shutdown)(struct of_device* dev); -- -- struct device_driver driver; --}; --#define to_of_platform_driver(drv) container_of(drv,struct of_platform_driver, driver) -- --extern int of_register_driver(struct of_platform_driver *drv); --extern void of_unregister_driver(struct of_platform_driver *drv); - extern int of_device_register(struct of_device *ofdev); - extern void of_device_unregister(struct of_device *ofdev); --extern struct of_device *of_platform_device_create(struct device_node *np, -- const char *bus_id, -- struct device *parent); - extern void of_release_dev(struct device *dev); - - #endif /* __KERNEL__ */ -diff --git a/include/asm-powerpc/of_platform.h b/include/asm-powerpc/of_platform.h -new file mode 100644 -index 0000000..217eafb ---- /dev/null -+++ b/include/asm-powerpc/of_platform.h -@@ -0,0 +1,60 @@ -+/* -+ * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp. -+ * -+ * -+ * 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 -+ -+/* -+ * The of_platform_bus_type is a bus type used by drivers that do not -+ * attach to a macio or similar bus but still use OF probing -+ * mechanism -+ */ -+extern struct bus_type of_platform_bus_type; -+ -+/* -+ * An of_platform_driver driver is attached to a basic of_device on -+ * the "platform bus" (of_platform_bus_type) -+ */ -+struct of_platform_driver -+{ -+ char *name; -+ struct of_device_id *match_table; -+ struct module *owner; -+ -+ int (*probe)(struct of_device* dev, -+ const struct of_device_id *match); -+ int (*remove)(struct of_device* dev); -+ -+ int (*suspend)(struct of_device* dev, pm_message_t state); -+ int (*resume)(struct of_device* dev); -+ int (*shutdown)(struct of_device* dev); -+ -+ struct device_driver driver; -+}; -+#define to_of_platform_driver(drv) \ -+ container_of(drv,struct of_platform_driver, driver) -+ -+/* Platform drivers register/unregister */ -+extern int of_register_platform_driver(struct of_platform_driver *drv); -+extern void of_unregister_platform_driver(struct of_platform_driver *drv); -+ -+/* Platform devices and busses creation */ -+extern struct of_device *of_platform_device_create(struct device_node *np, -+ const char *bus_id, -+ struct device *parent); -+/* pseudo "matches" value to not do deep probe */ -+#define OF_NO_DEEP_PROBE ((struct of_device_id *)-1) -+ -+extern int of_platform_bus_probe(struct device_node *root, -+ struct of_device_id *matches, -+ struct device *parent); -+ -+extern struct of_device *of_find_device_by_node(struct device_node *np); -+extern struct of_device *of_find_device_by_phandle(phandle ph); --- -1.4.3.2 - diff --git a/debian/patches/features/powerpc/efika/0012-ata-Fix-pata_mpc52xx.c-compatible-list.txt b/debian/patches/features/powerpc/efika/0012-ata-Fix-pata_mpc52xx.c-compatible-list.txt new file mode 100644 index 000000000..33f2ffcad --- /dev/null +++ b/debian/patches/features/powerpc/efika/0012-ata-Fix-pata_mpc52xx.c-compatible-list.txt @@ -0,0 +1,31 @@ +From 20e872b5fed46ba15ed6f2c29cc2adf98657c9a4 Mon Sep 17 00:00:00 2001 +From: Sylvain Munaut +Date: Sat, 23 Dec 2006 22:20:06 +0100 +Subject: [PATCH] [PATCH] ata: Fix pata_mpc52xx.c 'compatible' list + +The list contained an entry to support a non-standard device-tree, +this is now handled by fixups in early boot. + +Signed-off-by: Sylvain Munaut +--- + drivers/ata/pata_mpc52xx.c | 4 +--- + 1 files changed, 1 insertions(+), 3 deletions(-) + +diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c +index 8b7019a..ff40016 100644 +--- a/drivers/ata/pata_mpc52xx.c ++++ b/drivers/ata/pata_mpc52xx.c +@@ -509,9 +509,7 @@ mpc52xx_ata_resume(struct of_device *op) + + static struct of_device_id mpc52xx_ata_of_match[] = { + { +- .compatible = "mpc5200-ata", +- }, +- { ++ .type = "ata", + .compatible = "mpc52xx-ata", + }, + {}, +-- +1.4.4.2 + diff --git a/debian/patches/features/powerpc/efika/0013-powerpc-serial-Fix-mpc52xx_uart.c-compatible-list.txt b/debian/patches/features/powerpc/efika/0013-powerpc-serial-Fix-mpc52xx_uart.c-compatible-list.txt new file mode 100644 index 000000000..d0c5a4647 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0013-powerpc-serial-Fix-mpc52xx_uart.c-compatible-list.txt @@ -0,0 +1,28 @@ +From f3736d1a7f74d7dec888a8a8d8c593ca08a31000 Mon Sep 17 00:00:00 2001 +From: Sylvain Munaut +Date: Sat, 23 Dec 2006 22:21:43 +0100 +Subject: [PATCH] [PATCH] powerpc/serial: Fix mpc52xx_uart.c 'compatible' list + +The list contained an entry to support a non-standard device-tree, +this is now handled by fixups in early boot. + +Signed-off-by: Sylvain Munaut +--- + drivers/serial/mpc52xx_uart.c | 1 - + 1 files changed, 0 insertions(+), 1 deletions(-) + +diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c +index eef3b02..c20cd81 100644 +--- a/drivers/serial/mpc52xx_uart.c ++++ b/drivers/serial/mpc52xx_uart.c +@@ -128,7 +128,6 @@ static irqreturn_t mpc52xx_uart_int(int irq,void *dev_id); + #if defined(CONFIG_PPC_MERGE) + static struct of_device_id mpc52xx_uart_of_match[] = { + { .type = "serial", .compatible = "mpc52xx-psc-uart", }, +- { .type = "serial", .compatible = "mpc5200-psc", }, /* Efika only! */ + {}, + }; + #endif +-- +1.4.4.2 + diff --git a/debian/patches/features/powerpc/efika/0014-powerpc-Small-cleanup-of-EFIKA-platform.txt b/debian/patches/features/powerpc/efika/0014-powerpc-Small-cleanup-of-EFIKA-platform.txt new file mode 100644 index 000000000..a373e9703 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0014-powerpc-Small-cleanup-of-EFIKA-platform.txt @@ -0,0 +1,144 @@ +From 65cd4fcc30440e903fd99973918373ee4534b70a Mon Sep 17 00:00:00 2001 +From: Sylvain Munaut +Date: Sat, 23 Dec 2006 22:39:18 +0100 +Subject: [PATCH] [PATCH] powerpc: Small cleanup of EFIKA platform + +This is just some cleanup to remove the efika.h header that just have +2 lines in it and is not really necessary. + +Signed-off-by: Sylvain Munaut +--- + arch/powerpc/platforms/52xx/efika-pci.c | 23 ++++++++++++++++------- + arch/powerpc/platforms/52xx/efika-setup.c | 7 ++++--- + arch/powerpc/platforms/52xx/efika.h | 19 ------------------- + 3 files changed, 20 insertions(+), 29 deletions(-) + +diff --git a/arch/powerpc/platforms/52xx/efika-pci.c b/arch/powerpc/platforms/52xx/efika-pci.c +index 62e05b2..3732dec 100644 +--- a/arch/powerpc/platforms/52xx/efika-pci.c ++++ b/arch/powerpc/platforms/52xx/efika-pci.c +@@ -1,3 +1,13 @@ ++/* ++ * Efika 5K2 PCI support thru RTAS ++ * ++ * Copyright (C) 2006 bplan GmbH ++ * ++ * 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 + #include +@@ -12,7 +22,6 @@ + #include + #include + +-#include "efika.h" + + #ifdef CONFIG_PCI + /* +@@ -62,7 +71,7 @@ void __init efika_pcisetup(void) + + root = of_find_node_by_path("/"); + if (root == NULL) { +- printk(KERN_WARNING EFIKA_PLATFORM_NAME ++ printk(KERN_WARNING __FILE__ + ": Unable to find the root node\n"); + return; + } +@@ -76,30 +85,30 @@ void __init efika_pcisetup(void) + of_node_put(root); + + if (pcictrl == NULL) { +- printk(KERN_WARNING EFIKA_PLATFORM_NAME ++ printk(KERN_WARNING __FILE__ + ": Unable to find the PCI bridge node\n"); + return; + } + + bus_range = get_property(pcictrl, "bus-range", &len); + if (bus_range == NULL || len < 2 * sizeof(int)) { +- printk(KERN_WARNING EFIKA_PLATFORM_NAME ++ printk(KERN_WARNING __FILE__ + ": Can't get bus-range for %s\n", pcictrl->full_name); + return; + } + + if (bus_range[1] == bus_range[0]) +- printk(KERN_INFO EFIKA_PLATFORM_NAME ": PCI bus %d", ++ printk(KERN_INFO __FILE__ ": PCI bus %d", + bus_range[0]); + else +- printk(KERN_INFO EFIKA_PLATFORM_NAME ": PCI buses %d..%d", ++ printk(KERN_INFO __FILE__ ": PCI buses %d..%d", + bus_range[0], bus_range[1]); + printk(" controlled by %s\n", pcictrl->full_name); + printk("\n"); + + hose = pcibios_alloc_controller(); + if (!hose) { +- printk(KERN_WARNING EFIKA_PLATFORM_NAME ++ printk(KERN_WARNING __FILE__ + ": Can't allocate PCI controller structure for %s\n", + pcictrl->full_name); + return; +diff --git a/arch/powerpc/platforms/52xx/efika-setup.c b/arch/powerpc/platforms/52xx/efika-setup.c +index d61ce84..17bf73a 100644 +--- a/arch/powerpc/platforms/52xx/efika-setup.c ++++ b/arch/powerpc/platforms/52xx/efika-setup.c +@@ -1,5 +1,4 @@ + /* +- * + * Efika 5K2 platform setup + * Some code really inspired from the lite5200b platform. + * +@@ -32,7 +31,9 @@ + #include + #include + +-#include "efika.h" ++ ++extern void __init efika_pcisetup(void); ++ + + static void efika_show_cpuinfo(struct seq_file *m) + { +@@ -103,7 +104,7 @@ static int __init efika_probe(void) + + define_machine(efika) + { +- .name = EFIKA_PLATFORM_NAME, ++ .name = "Efika", + .probe = efika_probe, + .setup_arch = efika_setup_arch, + .init = mpc52xx_declare_of_platform_devices, +diff --git a/arch/powerpc/platforms/52xx/efika.h b/arch/powerpc/platforms/52xx/efika.h +deleted file mode 100644 +index 2f060fd..0000000 +--- a/arch/powerpc/platforms/52xx/efika.h ++++ /dev/null +@@ -1,19 +0,0 @@ +-/* +- * Efika 5K2 platform setup - Header file +- * +- * Copyright (C) 2006 bplan GmbH +- * +- * 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. +- * +- */ +- +-#ifndef __ARCH_POWERPC_EFIKA__ +-#define __ARCH_POWERPC_EFIKA__ +- +-#define EFIKA_PLATFORM_NAME "Efika" +- +-extern void __init efika_pcisetup(void); +- +-#endif +-- +1.4.4.2 + diff --git a/debian/patches/features/powerpc/efika/0015-powerpc-Add-a-unified-uevent-handler-for-bus-based-on-of_device.txt b/debian/patches/features/powerpc/efika/0015-powerpc-Add-a-unified-uevent-handler-for-bus-based-on-of_device.txt new file mode 100644 index 000000000..6de1fd28f --- /dev/null +++ b/debian/patches/features/powerpc/efika/0015-powerpc-Add-a-unified-uevent-handler-for-bus-based-on-of_device.txt @@ -0,0 +1,116 @@ +From 90dc591d4c897c7a49191888c1e4d413cc08b8b7 Mon Sep 17 00:00:00 2001 +From: Sylvain Munaut +Date: Sat, 23 Dec 2006 23:08:56 +0100 +Subject: [PATCH] [PATCH] powerpc: Add a unified uevent handler for bus based on of_device + +This common uevent handler allow the several bus types based on +of_device to generate the uevent properly and avoiding +code duplication. + +This handlers take a struct device as argument and can therefore +be used as the uevent call directly if no special treatment is +needed for the bus. + +Signed-off-by: Sylvain Munaut +--- + arch/powerpc/kernel/of_device.c | 66 +++++++++++++++++++++++++++++++++++++++ + include/asm-powerpc/of_device.h | 3 ++ + 2 files changed, 69 insertions(+), 0 deletions(-) + +diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c +index e921514..ac024ad 100644 +--- a/arch/powerpc/kernel/of_device.c ++++ b/arch/powerpc/kernel/of_device.c +@@ -120,6 +120,71 @@ void of_device_unregister(struct of_device *ofdev) + } + + ++int of_device_uevent(struct device *dev, ++ char **envp, int num_envp, char *buffer, int buffer_size) ++{ ++ struct of_device *ofdev; ++ const char *compat; ++ char *compat2; ++ char compat_buf[128]; /* need to be size of 'compatible' */ ++ int i = 0, length = 0, seen = 0, cplen, sl; ++ ++ if (!dev) ++ return -ENODEV; ++ ++ ofdev = to_of_device(dev); ++ ++ if (add_uevent_var(envp, num_envp, &i, ++ buffer, buffer_size, &length, ++ "OF_NAME=%s", ofdev->node->name)) ++ return -ENOMEM; ++ ++ if (add_uevent_var(envp, num_envp, &i, ++ buffer, buffer_size, &length, ++ "OF_TYPE=%s", ofdev->node->type)) ++ return -ENOMEM; ++ ++ /* Since the compatible field can contain pretty much anything ++ * it's not really legal to split it out with commas. We split it ++ * up using a number of environment variables instead. */ ++ ++ compat = get_property(ofdev->node, "compatible", &cplen); ++ compat2 = compat_buf; ++ if (compat) ++ memcpy(compat2, compat, cplen); ++ while (compat && *compat && cplen > 0) { ++ if (add_uevent_var(envp, num_envp, &i, ++ buffer, buffer_size, &length, ++ "OF_COMPATIBLE_%d=%s", seen, compat)) ++ return -ENOMEM; ++ ++ sl = strlen (compat) + 1; ++ compat += sl; ++ compat2 += sl; ++ cplen -= sl; ++ seen++; ++ compat2[-1] = 'C'; ++ } ++ compat2[seen?-1:0] = 0; ++ ++ if (add_uevent_var(envp, num_envp, &i, ++ buffer, buffer_size, &length, ++ "OF_COMPATIBLE_N=%d", seen)) ++ return -ENOMEM; ++ ++ if (add_uevent_var(envp, num_envp, &i, ++ buffer, buffer_size, &length, ++ "MODALIAS=of:N%sT%sC%s", ++ ofdev->node->name, ofdev->node->type, ++ compat_buf)) ++ return -ENOMEM; ++ ++ envp[i] = NULL; ++ ++ return 0; ++} ++ ++ + EXPORT_SYMBOL(of_match_node); + EXPORT_SYMBOL(of_match_device); + EXPORT_SYMBOL(of_device_register); +@@ -127,3 +192,4 @@ EXPORT_SYMBOL(of_device_unregister); + EXPORT_SYMBOL(of_dev_get); + EXPORT_SYMBOL(of_dev_put); + EXPORT_SYMBOL(of_release_dev); ++EXPORT_SYMBOL(of_device_uevent); +diff --git a/include/asm-powerpc/of_device.h b/include/asm-powerpc/of_device.h +index a889b20..4f1aabe 100644 +--- a/include/asm-powerpc/of_device.h ++++ b/include/asm-powerpc/of_device.h +@@ -32,5 +32,8 @@ extern int of_device_register(struct of_device *ofdev); + extern void of_device_unregister(struct of_device *ofdev); + extern void of_release_dev(struct device *dev); + ++extern int of_device_uevent(struct device *dev, ++ char **envp, int num_envp, char *buffer, int buffer_size); ++ + #endif /* __KERNEL__ */ + #endif /* _ASM_POWERPC_OF_DEVICE_H */ +-- +1.4.4.2 + diff --git a/debian/patches/features/powerpc/efika/0016-macintosh-Use-the-new-of_device-common-uevent-handler.txt b/debian/patches/features/powerpc/efika/0016-macintosh-Use-the-new-of_device-common-uevent-handler.txt new file mode 100644 index 000000000..93859bdeb --- /dev/null +++ b/debian/patches/features/powerpc/efika/0016-macintosh-Use-the-new-of_device-common-uevent-handler.txt @@ -0,0 +1,130 @@ +From 2507b27c0841752a6f419439896fcb089fa4a5ba Mon Sep 17 00:00:00 2001 +From: Sylvain Munaut +Date: Sat, 23 Dec 2006 23:13:56 +0100 +Subject: [PATCH] [PATCH] macintosh: Use the new of_device common uevent handler + +The generation of the uevent is now common to all bus using +of_device. + +Signed-off-by: Sylvain Munaut +--- + drivers/macintosh/macio_asic.c | 98 +--------------------------------------- + 1 files changed, 1 insertions(+), 97 deletions(-) + +diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c +index d562160..e851266 100644 +--- a/drivers/macintosh/macio_asic.c ++++ b/drivers/macintosh/macio_asic.c +@@ -134,108 +134,12 @@ static int macio_device_resume(struct device * dev) + return 0; + } + +-static int macio_uevent(struct device *dev, char **envp, int num_envp, +- char *buffer, int buffer_size) +-{ +- struct macio_dev * macio_dev; +- struct of_device * of; +- char *scratch; +- const char *compat, *compat2; +- +- int i = 0; +- int length, cplen, cplen2, seen = 0; +- +- if (!dev) +- return -ENODEV; +- +- macio_dev = to_macio_device(dev); +- if (!macio_dev) +- return -ENODEV; +- +- of = &macio_dev->ofdev; +- +- /* stuff we want to pass to /sbin/hotplug */ +- envp[i++] = scratch = buffer; +- length = scnprintf (scratch, buffer_size, "OF_NAME=%s", of->node->name); +- ++length; +- buffer_size -= length; +- if ((buffer_size <= 0) || (i >= num_envp)) +- return -ENOMEM; +- scratch += length; +- +- envp[i++] = scratch; +- length = scnprintf (scratch, buffer_size, "OF_TYPE=%s", of->node->type); +- ++length; +- buffer_size -= length; +- if ((buffer_size <= 0) || (i >= num_envp)) +- return -ENOMEM; +- scratch += length; +- +- /* Since the compatible field can contain pretty much anything +- * it's not really legal to split it out with commas. We split it +- * up using a number of environment variables instead. */ +- +- compat = get_property(of->node, "compatible", &cplen); +- compat2 = compat; +- cplen2= cplen; +- while (compat && cplen > 0) { +- envp[i++] = scratch; +- length = scnprintf (scratch, buffer_size, +- "OF_COMPATIBLE_%d=%s", seen, compat); +- ++length; +- buffer_size -= length; +- if ((buffer_size <= 0) || (i >= num_envp)) +- return -ENOMEM; +- scratch += length; +- length = strlen (compat) + 1; +- compat += length; +- cplen -= length; +- seen++; +- } +- +- envp[i++] = scratch; +- length = scnprintf (scratch, buffer_size, "OF_COMPATIBLE_N=%d", seen); +- ++length; +- buffer_size -= length; +- if ((buffer_size <= 0) || (i >= num_envp)) +- return -ENOMEM; +- scratch += length; +- +- envp[i++] = scratch; +- length = scnprintf (scratch, buffer_size, "MODALIAS=of:N%sT%s", +- of->node->name, of->node->type); +- /* overwrite '\0' */ +- buffer_size -= length; +- if ((buffer_size <= 0) || (i >= num_envp)) +- return -ENOMEM; +- scratch += length; +- +- if (!compat2) { +- compat2 = ""; +- cplen2 = 1; +- } +- while (cplen2 > 0) { +- length = snprintf (scratch, buffer_size, "C%s", compat2); +- buffer_size -= length; +- if (buffer_size <= 0) +- return -ENOMEM; +- scratch += length; +- length = strlen (compat2) + 1; +- compat2 += length; +- cplen2 -= length; +- } +- +- envp[i] = NULL; +- +- return 0; +-} +- + extern struct device_attribute macio_dev_attrs[]; + + struct bus_type macio_bus_type = { + .name = "macio", + .match = macio_bus_match, +- .uevent = macio_uevent, ++ .uevent = of_device_uevent, + .probe = macio_device_probe, + .remove = macio_device_remove, + .shutdown = macio_device_shutdown, +-- +1.4.4.2 + diff --git a/debian/patches/features/powerpc/efika/0017-powerpc-Add-uevent-handler-for-of_platform_bus.txt b/debian/patches/features/powerpc/efika/0017-powerpc-Add-uevent-handler-for-of_platform_bus.txt new file mode 100644 index 000000000..303cf6ba0 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0017-powerpc-Add-uevent-handler-for-of_platform_bus.txt @@ -0,0 +1,29 @@ +From 846d6cd8584eee7517543be073c8b3fe9fefd065 Mon Sep 17 00:00:00 2001 +From: Sylvain Munaut +Date: Sat, 23 Dec 2006 23:16:07 +0100 +Subject: [PATCH] [PATCH] powerpc: Add uevent handler for of_platform_bus + +Adding this handler allow userspace to properly handle the module +autoloading. The generation of the uevent itself is now common to +all bus using of_device, so not much code here. + +Signed-off-by: Sylvain Munaut +--- + arch/powerpc/kernel/of_platform.c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c +index b734517..da78e44 100644 +--- a/arch/powerpc/kernel/of_platform.c ++++ b/arch/powerpc/kernel/of_platform.c +@@ -133,6 +133,7 @@ static int of_platform_device_resume(struct device * dev) + struct bus_type of_platform_bus_type = { + .name = "of_platform", + .match = of_platform_bus_match, ++ .uevent = of_device_uevent, + .probe = of_platform_device_probe, + .remove = of_platform_device_remove, + .suspend = of_platform_device_suspend, +-- +1.4.4.2 + diff --git a/debian/patches/features/powerpc/efika/0018-powerpc-Add-uevent-handler-for-ibmebus.txt b/debian/patches/features/powerpc/efika/0018-powerpc-Add-uevent-handler-for-ibmebus.txt new file mode 100644 index 000000000..39392a606 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0018-powerpc-Add-uevent-handler-for-ibmebus.txt @@ -0,0 +1,50 @@ +From ddc4a7296f3abd28a902f38ae915224d6d93edca Mon Sep 17 00:00:00 2001 +From: Sylvain Munaut +Date: Sat, 23 Dec 2006 23:20:58 +0100 +Subject: [PATCH] [PATCH] powerpc: Add uevent handler for ibmebus + +Adding this handler allow userspace to properly handle the module +autoloading. The generation of the uevent itself is now common to +all bus using of_device, so not much code here. + +But we still need a small wrapper to filter out the dummy root +device node used by this bus. + +Signed-off-by: Sylvain Munaut +--- + arch/powerpc/kernel/ibmebus.c | 16 ++++++++++++++++ + 1 files changed, 16 insertions(+), 0 deletions(-) + +diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c +index 82bd2f1..2e8d9fd 100644 +--- a/arch/powerpc/kernel/ibmebus.c ++++ b/arch/powerpc/kernel/ibmebus.c +@@ -361,9 +361,25 @@ static int ibmebus_bus_match(struct device *dev, struct device_driver *drv) + return 0; + } + ++static int ibmebus_bus_uevent(struct device *dev, ++ char **envp, int num_envp, char *buffer, int buffer_size) ++{ ++ struct ibmebus_dev *ebus_dev; ++ ++ if (!dev) ++ return -ENODEV; ++ ++ ebus_dev = to_ibmebus_dev(dev); ++ if (ebus_dev==ibmebus_bus_device) /* filter dummy root device */ ++ return -ENODEV; ++ ++ return of_device_uevent(dev, envp, num_envp, buffer, buffer_size); ++} ++ + struct bus_type ibmebus_bus_type = { + .name = "ibmebus", + .match = ibmebus_bus_match, ++ .uevent = ibmebus_bus_uevent, + }; + EXPORT_SYMBOL(ibmebus_bus_type); + +-- +1.4.4.2 + diff --git a/debian/patches/features/powerpc/efika/0019-MPC5200-Bestcomm-platform-driver.txt b/debian/patches/features/powerpc/efika/0019-MPC5200-Bestcomm-platform-driver.txt new file mode 100644 index 000000000..74bfbf9b3 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0019-MPC5200-Bestcomm-platform-driver.txt @@ -0,0 +1,1439 @@ +From d9e27abf78b3bd714eb9c37c529d0bff7c5403d9 Mon Sep 17 00:00:00 2001 +From: Andrey Volkov +Date: Fri, 18 Aug 2006 10:01:38 -0600 +Subject: [PATCH] [PATCH 01/02] MPC5200 Bestcomm platform driver + +This is first part of "platformizied" bestcomm/fec drivers. + +Signed-Off-By: Andrey Volkov +--- + arch/ppc/Kconfig | 5 + + arch/ppc/syslib/Makefile | 1 + + arch/ppc/syslib/bestcomm/Makefile | 2 + + arch/ppc/syslib/bestcomm/bestcomm.c | 408 +++++++++++++++++++++++ + arch/ppc/syslib/bestcomm/bestcomm.h | 473 +++++++++++++++++++++++++++ + arch/ppc/syslib/bestcomm/fec.c | 174 ++++++++++ + arch/ppc/syslib/bestcomm/fec.h | 71 ++++ + arch/ppc/syslib/bestcomm/sdma_fec_rx_task.c | 71 ++++ + arch/ppc/syslib/bestcomm/sdma_fec_tx_task.c | 84 +++++ + arch/ppc/syslib/mpc52xx_devices.c | 22 ++ + arch/ppc/syslib/mpc52xx_sys.c | 4 +- + include/asm-ppc/mpc52xx.h | 2 + + 12 files changed, 1315 insertions(+), 2 deletions(-) + +diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig +index 8eb82ef..d8a561e 100644 +--- a/arch/ppc/Kconfig ++++ b/arch/ppc/Kconfig +@@ -775,6 +775,11 @@ config EMBEDDEDBOOT + config PPC_MPC52xx + bool + ++config PPC_BESTCOMM ++ bool ++ depends on PPC_MPC52xx ++ default y ++ + config 8260 + bool "CPM2 Support" if WILLOW + depends on 6xx +diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile +index dca23f2..ab015df 100644 +--- a/arch/ppc/syslib/Makefile ++++ b/arch/ppc/syslib/Makefile +@@ -106,3 +106,4 @@ obj-$(CONFIG_PCI) += mpc52xx_pci.o + endif + + obj-$(CONFIG_PPC_I8259) += i8259.o ++obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/ +diff --git a/arch/ppc/syslib/bestcomm/Makefile b/arch/ppc/syslib/bestcomm/Makefile +new file mode 100644 +index 0000000..02cc99a +--- /dev/null ++++ b/arch/ppc/syslib/bestcomm/Makefile +@@ -0,0 +1,2 @@ ++obj-$(CONFIG_PPC_BESTCOMM) += bestcomm.o ++obj-$(CONFIG_FEC_MPC52xx) += sdma_fec_rx_task.o sdma_fec_tx_task.o fec.o +diff --git a/arch/ppc/syslib/bestcomm/bestcomm.c b/arch/ppc/syslib/bestcomm/bestcomm.c +new file mode 100644 +index 0000000..ef45e02 +--- /dev/null ++++ b/arch/ppc/syslib/bestcomm/bestcomm.c +@@ -0,0 +1,408 @@ ++/* ++ * arch/ppc/syslib/bestcomm/bestcomm.c ++ * ++ * Driver for MPC52xx processor BestComm peripheral controller ++ * ++ * Author: Dale Farnsworth ++ * ++ * 2003-2004 (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. ++ * ++ * HISTORY: ++ * ++ * 2005-08-14 Converted to platform driver by ++ * Andrey Volkov , Varma Electronics Oy ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "bestcomm.h" ++ ++#define DRIVER_NAME "mpc52xx-sdma" ++ ++struct sdma_io sdma; ++ ++static spinlock_t sdma_lock = SPIN_LOCK_UNLOCKED; ++ ++#ifdef CONFIG_BESTCOMM_DEBUG ++void sdma_dump(void) ++{ ++ int i; ++ printk("** SDMA registers: pa = %08x, va = %08x\n", sdma.base_reg_addr, sdma.io); ++ printk("** taskBar = %08x\n", sdma.io->taskBar); ++ printk("** currentPointer = %08x\n", sdma.io->currentPointer); ++ printk("** endPointer = %08x\n", sdma.io->endPointer); ++ printk("** variablePointer = %08x\n", sdma.io->variablePointer); ++ ++ printk("** IntVect1 = %08x\n", sdma.io->IntVect1); ++ printk("** IntVect2 = %08x\n", sdma.io->IntVect2); ++ printk("** PtdCntrl = %08x\n", sdma.io->PtdCntrl); ++ ++ printk("** IntPend = %08x\n", sdma.io->IntPend); ++ printk("** IntMask = %08x\n", sdma.io->IntMask); ++ ++ printk("** TCR dump:"); ++ ++ for (i=0;i<16;i++) { ++ if(i%8 == 0) ++ printk("\n** %02X:",i); ++ printk(" %04X",sdma.io->tcr[i]); ++ } ++ printk("\n** IPR dump:"); ++ for (i=0;i<32;i++) { ++ if(i%16 == 0) ++ printk("\n** %02X:",i); ++ printk(" %02X",sdma.io->ipr[i]); ++ } ++ printk("\n** cReqSelect = %08x\n", sdma.io->cReqSelect); ++ printk("** task_size0 = %08x\n", sdma.io->task_size0); ++ printk("** task_size1 = %08x\n", sdma.io->task_size1); ++ printk("** MDEDebug = %08x\n", sdma.io->MDEDebug); ++ printk("** ADSDebug = %08x\n", sdma.io->ADSDebug); ++ printk("** Value1 = %08x\n", sdma.io->Value1); ++ printk("** Value2 = %08x\n", sdma.io->Value2); ++ printk("** Control = %08x\n", sdma.io->Control); ++ printk("** Status = %08x\n", sdma.io->Status); ++ printk("** PTDDebug = %08x\n", sdma.io->PTDDebug); ++} ++#endif ++ ++#ifdef CONFIG_BESTCOMM_DEBUG ++#define SDMA_DUMP_REGS() sdma_dump() ++#else ++#define SDMA_DUMP_REGS() ++#endif ++ ++/* ++ * Use a very simple SRAM allocator. ++ * There is no mechanism for freeing space. ++ * In an attempt to minimize internal fragmentation, the SRAM is ++ * divided into two areas. ++ * ++ * Area 1 is at the beginning of SRAM ++ * and is used for allocations requiring alignments of 16 bytes or less. ++ * Successive allocations return higher addresses. ++ * ++ * Area 2 is at the end of SRAM and is used for the remaining allocations. ++ * Successive allocations return lower addresses. ++ * ++ * I've considered adding routines to support the freeing of SRAM allocations, ++ * but the SRAM is so small (16K) that fragmentation can quickly cause the ++ * SRAM to be unusable. If you can come up with a slick way to free SRAM ++ * memory without the fragmentation problem, please do so. ++ */ ++ ++static u8 *area1_end; ++static u8 *area2_begin; ++ ++void *sdma_sram_alloc(int size, int alignment, u32 *dma_handle) ++{ ++ u8 *a; ++ ++ spin_lock(&sdma_lock); ++ ++ /* alignment must be a power of 2 */ ++ BUG_ON(alignment & (alignment - 1)); ++ ++ if (alignment < 16) { ++ a = (u8 *)(((u32)area1_end + (alignment-1)) & ~(alignment-1)); ++ if (a + size <= area2_begin) ++ area1_end = a + size; ++ else ++ a = 0; /* out of memory */ ++ } else { ++ a = (u8 *)(((u32)area2_begin - size) & ~(alignment - 1)); ++ if (a >= area1_end) ++ area2_begin = a; ++ else ++ a = 0; /* out of memory */ ++ } ++ if(a && dma_handle) ++ *dma_handle = sdma_sram_pa(a); ++ spin_unlock(&sdma_lock); ++ return (void *)a; ++} ++ ++/* this will need to be updated if Freescale changes their task code FDT */ ++static u32 fdt_ops[] = { ++ 0xa0045670, /* FDT[48] */ ++ 0x80045670, /* FDT[49] */ ++ 0x21800000, /* FDT[50] */ ++ 0x21e00000, /* FDT[51] */ ++ 0x21500000, /* FDT[52] */ ++ 0x21400000, /* FDT[53] */ ++ 0x21500000, /* FDT[54] */ ++ 0x20400000, /* FDT[55] */ ++ 0x20500000, /* FDT[56] */ ++ 0x20800000, /* FDT[57] */ ++ 0x20a00000, /* FDT[58] */ ++ 0xc0170000, /* FDT[59] */ ++ 0xc0145670, /* FDT[60] */ ++ 0xc0345670, /* FDT[61] */ ++ 0xa0076540, /* FDT[62] */ ++ 0xa0000760, /* FDT[63] */ ++}; ++ ++static int new_task_number(void) ++{ ++ struct sdma_tdt *tdt; ++ int i; ++ ++ spin_lock(&sdma_lock); ++ ++ tdt = sdma.tdt; ++ for (i=0; istart == 0) ++ break; ++ if (i == SDMA_MAX_TASKS) ++ i = -1; ++ ++ spin_unlock(&sdma_lock); ++ ++ return i; ++} ++ ++int sdma_load_task(u32 *task_image) ++{ ++ struct sdma_task_header *head = (struct sdma_task_header *)task_image; ++ struct sdma_tdt *tdt; ++ int tasknum; ++ u32 *desc; ++ u32 *var_src, *var_dst; ++ u32 *inc_src; ++ void *start; ++ ++ BUG_ON(head->magic != SDMA_TASK_MAGIC); ++ ++ tasknum = new_task_number(); ++ if (tasknum < 0) ++ return -ENOMEM; ++ ++ desc = (u32 *)(head + 1); ++ var_src = desc + head->desc_size; ++ inc_src = var_src + head->var_size; ++ ++ tdt = &sdma.tdt[tasknum]; ++ ++ start = sdma_sram_alloc(head->desc_size * sizeof(u32), 4, &tdt->start); ++ if (!start) ++ return -ENOMEM; ++ tdt->stop = tdt->start + (head->desc_size - 1)*sizeof(u32); ++ var_dst = sdma_sram_va(tdt->var); ++ ++ memcpy(start, desc, head->desc_size * sizeof(u32)); ++ memcpy(&var_dst[head->first_var], var_src, head->var_size * sizeof(u32)); ++ memcpy(&var_dst[SDMA_MAX_VAR], inc_src, head->inc_size * sizeof(u32)); ++ ++ return tasknum; ++} ++ ++void sdma_set_initiator(int task, int initiator) ++{ ++ int i; ++ int num_descs; ++ u32 *desc; ++ int next_drd_has_initiator; ++ ++ sdma_set_tcr_initiator(task, initiator); ++ ++ desc = sdma_task_desc(task); ++ next_drd_has_initiator = 1; ++ num_descs = sdma_task_num_descs(task); ++ ++ for (i=0; icookie = cookie; ++ } ++ ++ s->num_bd = queue_size; ++ return s; ++} ++ ++void sdma_free(struct sdma *s) ++{ ++ if (s->cookie) ++ kfree(s->cookie); ++ kfree(s); ++} ++ ++static int __devinit mpc52xx_sdma_probe(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ int task; ++ u32 *context; ++ u32 *fdt; ++ struct sdma_tdt *tdt; ++ struct resource *mem_io, *mem_sram; ++ u32 tdt_pa, var_pa, context_pa, fdt_pa; ++ int ret = -ENODEV; ++ ++ mem_io = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ mem_sram = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ if (!mem_io || !mem_sram) ++ goto out; ++ ++ if (!request_mem_region(mem_io->start, mem_io->end - mem_io->start + 1, DRIVER_NAME)) { ++ printk(KERN_ERR DRIVER_NAME " - resource unavailable\n"); ++ goto out; ++ } ++ sdma.base_reg_addr = mem_io->start; ++ ++ sdma.io = ioremap_nocache(mem_io->start, sizeof(struct mpc52xx_sdma)); ++ ++ if (!sdma.io ) { ++ printk(KERN_ERR DRIVER_NAME " - failed to map sdma regs\n"); ++ ret = -ENOMEM; ++ goto map_io_error; ++ } ++ ++ SDMA_DUMP_REGS(); ++ ++ sdma.sram_size = mem_sram->end - mem_sram->start + 1; ++ if (!request_mem_region(mem_sram->start, sdma.sram_size, DRIVER_NAME)) { ++ printk(KERN_ERR DRIVER_NAME " - resource unavailable\n"); ++ goto req_sram_error; ++ } ++ ++ sdma.base_sram_addr = mem_sram->start; ++ sdma.sram = ioremap_nocache(mem_sram->start, sdma.sram_size); ++ if (!sdma.sram ) { ++ printk(KERN_ERR DRIVER_NAME " - failed to map sdma sram\n"); ++ ret = -ENOMEM; ++ goto map_sram_error; ++ } ++ ++ area1_end = sdma.sram; ++ area2_begin = area1_end + sdma.sram_size; ++ ++ memset(area1_end, 0, sdma.sram_size); ++ ++ /* allocate space for task descriptors, contexts, and var tables */ ++ sdma.tdt = sdma_sram_alloc(sizeof(struct sdma_tdt) * SDMA_MAX_TASKS, 4, &tdt_pa); ++ ++ context = sdma_sram_alloc(SDMA_CONTEXT_SIZE * SDMA_MAX_TASKS, ++ SDMA_CONTEXT_ALIGN, &context_pa); ++ sdma.var = sdma_sram_alloc( (SDMA_VAR_SIZE + SDMA_INC_SIZE) * SDMA_MAX_TASKS, ++ SDMA_VAR_ALIGN, &var_pa); ++ fdt = sdma_sram_alloc(SDMA_FDT_SIZE, SDMA_FDT_ALIGN, &fdt_pa); ++ memcpy(&fdt[48], fdt_ops, sizeof(fdt_ops)); ++ ++ out_be32(&sdma.io->taskBar, tdt_pa); ++ ++ tdt = sdma.tdt; ++ for (task=0; task < SDMA_MAX_TASKS; task++) { ++ out_be16(&sdma.io->tcr[task], 0); ++ out_8(&sdma.io->ipr[task], 0); ++ ++ tdt->context = context_pa; ++ tdt->var = var_pa; ++ tdt->fdt = fdt_pa; ++ var_pa += (SDMA_MAX_VAR + SDMA_MAX_INC)*sizeof(u32); ++ context_pa += SDMA_MAX_CONTEXT*sizeof(u32); ++ tdt++; ++ } ++ ++ out_8(&sdma.io->ipr[SDMA_INITIATOR_ALWAYS], SDMA_IPR_ALWAYS); ++ ++ /* Disable COMM Bus Prefetch, apparently it's not reliable yet */ ++ out_be16(&sdma.io->PtdCntrl, in_be16(&sdma.io->PtdCntrl) | 1); ++ ++ printk(KERN_INFO "MPC52xx BestComm inited\n"); ++ ++ return 0; ++ ++map_sram_error: ++ release_mem_region(mem_sram->start, sdma.sram_size); ++req_sram_error: ++ iounmap(sdma.io); ++map_io_error: ++ release_mem_region(mem_io->start, mem_io->end - mem_io->start + 1); ++out: ++ printk(KERN_ERR "DMA: MPC52xx BestComm init FAILED !!!\n"); ++ return ret; ++} ++ ++ ++static struct device_driver mpc52xx_sdma_driver = { ++ .owner = THIS_MODULE, ++ .name = DRIVER_NAME, ++ .bus = &platform_bus_type, ++ .probe = mpc52xx_sdma_probe, ++/* .remove = mpc52xx_sdma_remove, TODO */ ++#ifdef CONFIG_PM ++/* .suspend = mpc52xx_sdma_suspend, TODO */ ++/* .resume = mpc52xx_sdma_resume, TODO */ ++#endif ++}; ++ ++static int __init ++mpc52xx_sdma_init(void) ++{ ++ printk(KERN_INFO "DMA: MPC52xx BestComm driver\n"); ++ return driver_register(&mpc52xx_sdma_driver); ++} ++ ++#ifdef MODULE ++static void __exit ++mpc52xx_sdma_exit(void) ++{ ++ driver_unregister(&mpc52xx_sdma_driver); ++} ++#endif ++ ++#ifndef MODULE ++ subsys_initcall(mpc52xx_sdma_init); ++#else ++ module_init(mpc52xx_sdma_init); ++ module_exit(mpc52xx_sdma_exit); ++#endif ++ ++ ++MODULE_DESCRIPTION("Freescale MPC52xx BestComm DMA"); ++MODULE_LICENSE("GPL"); ++ ++EXPORT_SYMBOL(sdma_sram_alloc); ++EXPORT_SYMBOL(sdma_load_task); ++EXPORT_SYMBOL(sdma_set_initiator); ++EXPORT_SYMBOL(sdma_free); ++EXPORT_SYMBOL(sdma); ++ ++ +diff --git a/arch/ppc/syslib/bestcomm/bestcomm.h b/arch/ppc/syslib/bestcomm/bestcomm.h +new file mode 100644 +index 0000000..14bf397 +--- /dev/null ++++ b/arch/ppc/syslib/bestcomm/bestcomm.h +@@ -0,0 +1,473 @@ ++/* ++ * arch/ppc/syslib/bestcomm/bestcomm.h ++ * ++ * Driver for MPC52xx processor BestComm peripheral controller ++ * ++ * Author: Dale Farnsworth ++ * ++ * 2003-2004 (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. ++ * ++ * HISTORY: ++ * ++ * 2005-08-14 Converted to platform driver by ++ * Andrey Volkov , Varma Electronics Oy ++ */ ++ ++#ifndef __BESTCOMM_BESTCOMM_H__ ++#define __BESTCOMM_BESTCOMM_H__ ++ ++/* Buffer Descriptor definitions */ ++struct sdma_bd { ++ u32 status; ++ void *data; ++}; ++ ++struct sdma_bd2 { ++ u32 status; ++ void *data1; ++ void *data2; ++}; ++ ++struct sdma_io { ++ unsigned long base_reg_addr; ++ struct mpc52xx_sdma __iomem *io; ++ unsigned long base_sram_addr; ++ void __iomem *sram; ++ size_t sram_size; ++ ++ struct sdma_tdt __iomem *tdt; ++ u32 __iomem *var; ++}; ++extern struct sdma_io sdma; ++ ++#define sdma_sram_pa(virt) (((unsigned long)(((void __iomem *)(virt))-sdma.sram))+sdma.base_sram_addr) ++#define sdma_sram_va(pa) ((void __iomem *)((((unsigned long)(pa))-sdma.base_sram_addr)+((unsigned long)sdma.sram))) ++ ++#define sdma_io_pa(virt) (((unsigned long)(((void __iomem *)(virt))-((void __iomem *)sdma.io)))+sdma.base_reg_addr) ++#define sdma_io_va(pa) ((void __iomem *)((((unsigned long)(pa))-sdma.base_reg_addr)+((unsigned long)sdma.io))) ++ ++#define SDMA_LEN_BITS 26 ++#define SDMA_LEN_MASK ((1 << SDMA_LEN_BITS) - 1) ++ ++#define SDMA_BD_READY 0x40000000UL ++ ++#define SDMA_FEC_TX_BD_TFD 0x08000000UL /* transmit frame done */ ++#define SDMA_FEC_TX_BD_INT 0x04000000UL /* Interrupt */ ++#define SDMA_FEC_TX_BD_TFD_INIT (SDMA_BD_READY | SDMA_FEC_TX_BD_TFD | \ ++ SDMA_FEC_TX_BD_INT) ++ ++struct sdma { ++ union { ++ struct sdma_bd *bd; ++ struct sdma_bd2 *bd2; ++ }; ++ void **cookie; ++ u16 index; ++ u16 outdex; ++ u16 num_bd; ++ s16 tasknum; ++ u32 flags; ++}; ++ ++#define SDMA_FLAGS_NONE 0x0000 ++#define SDMA_FLAGS_ENABLE_TASK 0x0001 ++#define SDMA_FLAGS_BD2 0x0002 ++ ++/* Task Descriptor Table Entry */ ++struct sdma_tdt { ++ u32 start; ++ u32 stop; ++ u32 var; ++ u32 fdt; ++ u32 exec_status; /* used internally by SmartComm engine */ ++ u32 mvtp; /* used internally by SmartComm engine */ ++ u32 context; ++ u32 litbase; ++}; ++ ++//extern struct sdma_tdt *sdma_tdt; ++ ++#define SDMA_MAX_TASKS 16 ++#define SDMA_MAX_VAR 24 ++#define SDMA_MAX_INC 8 ++#define SDMA_MAX_FDT 64 ++#define SDMA_MAX_CONTEXT 20 ++#define SDMA_CONTEXT_SIZE SDMA_MAX_CONTEXT * sizeof(u32) ++#define SDMA_CONTEXT_ALIGN 0x100 ++#define SDMA_VAR_SIZE SDMA_MAX_VAR * sizeof(u32) ++#define SDMA_VAR_ALIGN 0x80 ++#define SDMA_INC_SIZE SDMA_MAX_INC * sizeof(u32) ++#define SDMA_FDT_SIZE SDMA_MAX_FDT * sizeof(u32) ++#define SDMA_FDT_ALIGN 0x100 ++#define SDMA_BD_ALIGN 0x10 ++ ++#define TASK_ENABLE 0x8000 ++ ++#ifndef DPRINK ++ #ifdef CONFIG_BESTCOMM_DEBUG ++ #define DPRINTK(a,b...) printk(KERN_DEBUG "sdma: %s: " a, __FUNCTION__ , ## b) ++ #else ++ #define DPRINTK(a,b...) ++ #endif ++#endif ++ ++static inline void sdma_enable_task(int task) ++{ ++ DPRINTK("***DMA enable task (%d): tdt = %08x\n",task, sdma.tdt); ++ DPRINTK("***tdt->start = %08x\n",sdma.tdt[task].start); ++ DPRINTK("***tdt->stop = %08x\n",sdma.tdt[task].stop); ++ DPRINTK("***tdt->var = %08x\n",sdma.tdt[task].var); ++ DPRINTK("***tdt->fdt = %08x\n",sdma.tdt[task].fdt); ++ DPRINTK("***tdt->status = %08x\n",sdma.tdt[task].exec_status); ++ DPRINTK("***tdt->mvtp = %08x\n",sdma.tdt[task].mvtp); ++ DPRINTK("***tdt->context = %08x\n",sdma.tdt[task].context); ++ DPRINTK("***tdt->litbase = %08x\n",sdma.tdt[task].litbase); ++ DPRINTK("***--------------\n"); ++ ++ u16 reg = in_be16(&sdma.io->tcr[task]); ++ DPRINTK("***enable task: &sdma.io->tcr=%08x, reg = %04x\n", &sdma.io->tcr, reg); ++ out_be16(&sdma.io->tcr[task], reg | TASK_ENABLE); ++} ++ ++static inline void sdma_disable_task(int task) ++{ ++ u16 reg = in_be16(&sdma.io->tcr[task]); ++ DPRINTK("***disable task(%d): reg = %04x\n", task, reg); ++ out_be16(&sdma.io->tcr[task], reg & ~TASK_ENABLE); ++} ++ ++static inline int sdma_irq(struct sdma *s) ++{ ++ return MPC52xx_SDMA_IRQ_BASE + s->tasknum; ++} ++ ++static inline void sdma_enable(struct sdma *s) ++{ ++ sdma_enable_task(s->tasknum); ++} ++ ++static inline void sdma_disable(struct sdma *s) ++{ ++ sdma_disable_task(s->tasknum); ++} ++ ++static inline int sdma_queue_empty(struct sdma *s) ++{ ++ return s->index == s->outdex; ++} ++ ++static inline void sdma_clear_irq(struct sdma *s) ++{ ++ out_be32(&sdma.io->IntPend, 1 << s->tasknum); ++} ++ ++static inline int sdma_next_index(struct sdma *s) ++{ ++ return ((s->index + 1) == s->num_bd) ? 0 : s->index + 1; ++} ++ ++static inline int sdma_next_outdex(struct sdma *s) ++{ ++ return ((s->outdex + 1) == s->num_bd) ? 0 : s->outdex + 1; ++} ++ ++static inline int sdma_queue_full(struct sdma *s) ++{ ++ return s->outdex == sdma_next_index(s); ++} ++ ++static inline int sdma_buffer_done(struct sdma *s) ++{ ++#ifdef CONFIG_BESTCOMM_DEBUG ++ BUG_ON(s->flags & SDMA_FLAGS_BD2); ++#endif ++ if (sdma_queue_empty(s)) ++ return 0; ++ return (s->bd[s->outdex].status & SDMA_BD_READY) == 0; ++} ++ ++static inline int sdma_buffer2_done(struct sdma *s) ++{ ++#ifdef CONFIG_BESTCOMM_DEBUG ++ BUG_ON(!(s->flags & SDMA_FLAGS_BD2)); ++#endif ++ if (sdma_queue_empty(s)) ++ return 0; ++ ++ return (s->bd2[s->outdex].status & SDMA_BD_READY) == 0; ++} ++ ++static inline u32 *sdma_task_desc(int task) ++{ ++ return sdma_sram_va(sdma.tdt[task].start); ++} ++ ++static inline u32 sdma_task_num_descs(int task) ++{ ++ return (sdma.tdt[task].stop - sdma.tdt[task].start)/sizeof(u32) + 1; ++} ++ ++static inline u32 *sdma_task_var(int task) ++{ ++ return sdma_sram_va(sdma.tdt[task].var); ++} ++ ++static inline u32 *sdma_task_inc(int task) ++{ ++ return &sdma_task_var(task)[SDMA_MAX_VAR]; ++} ++ ++static inline void sdma_set_tcr_initiator(int task, int initiator) { ++ u16 *tcr = &sdma.io->tcr[task]; ++ out_be16(tcr, (in_be16(tcr) & ~0x1f00) | (initiator << 8)); ++} ++ ++#define SDMA_DRD_INITIATOR_SHIFT 21 ++ ++static inline int sdma_desc_initiator(u32 desc) ++{ ++ return (desc >> SDMA_DRD_INITIATOR_SHIFT) & 0x1f; ++} ++ ++static inline void sdma_set_desc_initiator(u32 *desc, int initiator) ++{ ++ *desc = (*desc & ~(0x1f << SDMA_DRD_INITIATOR_SHIFT)) | ++ ((initiator << SDMA_DRD_INITIATOR_SHIFT) & 0x1f); ++} ++ ++static inline void sdma_submit_buffer(struct sdma *s, void *cookie, void *data, ++ int length) ++{ ++#ifdef CONFIG_BESTCOMM_DEBUG ++ BUG_ON(s->flags & SDMA_FLAGS_BD2); ++#endif ++ s->cookie[s->index] = cookie; ++ s->bd[s->index].data = data; ++ s->bd[s->index].status = SDMA_BD_READY | length; ++ s->index = sdma_next_index(s); ++ if (s->flags & SDMA_FLAGS_ENABLE_TASK) ++ sdma_enable_task(s->tasknum); ++} ++ ++/* ++ * Special submit_buffer function to submit last buffer of a frame to ++ * the FEC tx task. tfd means "transmit frame done". ++ */ ++static inline void sdma_fec_tfd_submit_buffer(struct sdma *s, void *cookie, ++ void *data, int length) ++{ ++#ifdef CONFIG_BESTCOMM_DEBUG ++ BUG_ON(s->flags & SDMA_FLAGS_BD2); ++#endif ++ s->cookie[s->index] = cookie; ++ s->bd[s->index].data = data; ++ s->bd[s->index].status = SDMA_FEC_TX_BD_TFD_INIT | length; ++ s->index = sdma_next_index(s); ++ sdma_enable_task(s->tasknum); ++} ++ ++static inline void *sdma_retrieve_buffer(struct sdma *s, int *length) ++{ ++ void *cookie = s->cookie[s->outdex]; ++ ++#ifdef CONFIG_BESTCOMM_DEBUG ++ BUG_ON(s->flags & SDMA_FLAGS_BD2); ++#endif ++ if (length) ++ *length = s->bd[s->outdex].status & SDMA_LEN_MASK; ++ s->outdex = sdma_next_outdex(s); ++ return cookie; ++} ++ ++static inline void sdma_submit_buffer2(struct sdma *s, void *cookie, ++ void *data1, void *data2, int length) ++{ ++#ifdef CONFIG_BESTCOMM_DEBUG ++ BUG_ON(!(s->flags & SDMA_FLAGS_BD2)); ++#endif ++ s->cookie[s->index] = cookie; ++ s->bd2[s->index].data1 = data1; ++ s->bd2[s->index].data2 = data2; ++ s->bd2[s->index].status = SDMA_BD_READY | length; ++ s->index = sdma_next_index(s); ++ if (s->flags & SDMA_FLAGS_ENABLE_TASK) ++ sdma_enable_task(s->tasknum); ++} ++ ++static inline void *sdma_retrieve_buffer2(struct sdma *s, int *length) ++{ ++ void *cookie = s->cookie[s->outdex]; ++ ++#ifdef CONFIG_BESTCOMM_DEBUG ++ BUG_ON(!(s->flags & SDMA_FLAGS_BD2)); ++#endif ++ if (length) ++ *length = s->bd2[s->outdex].status & SDMA_LEN_MASK; ++ s->outdex = sdma_next_outdex(s); ++ return cookie; ++} ++ ++#define SDMA_TASK_MAGIC 0x4243544B /* 'BCTK' */ ++ ++/* the size fields are given in number of 32-bit words */ ++struct sdma_task_header { ++ u32 magic; ++ u8 desc_size; ++ u8 var_size; ++ u8 inc_size; ++ u8 first_var; ++ u8 reserved[8]; ++}; ++ ++#define SDMA_DESC_NOP 0x000001f8 ++#define SDMA_LCD_MASK 0x80000000 ++#define SDMA_DRD_EXTENDED 0x40000000 ++ ++#define sdma_drd_is_extended(desc) ((desc) & SDMA_DRD_EXTENDED) ++ ++static inline int sdma_desc_is_drd(u32 desc) { ++ return !(desc & SDMA_LCD_MASK) && desc != SDMA_DESC_NOP; ++}; ++ ++#define SDMA_PRAGMA_BIT_RSV 7 /* reserved pragma bit */ ++#define SDMA_PRAGMA_BIT_PRECISE_INC 6 /* increment 0=when possible, */ ++ /* 1=iter end */ ++#define SDMA_PRAGMA_BIT_RST_ERROR_NO 5 /* don't reset errors on */ ++ /* task enable */ ++#define SDMA_PRAGMA_BIT_PACK 4 /* pack data enable */ ++#define SDMA_PRAGMA_BIT_INTEGER 3 /* data alignment */ ++ /* 0=frac(msb), 1=int(lsb) */ ++#define SDMA_PRAGMA_BIT_SPECREAD 2 /* XLB speculative read */ ++#define SDMA_PRAGMA_BIT_CW 1 /* write line buffer enable */ ++#define SDMA_PRAGMA_BIT_RL 0 /* read line buffer enable */ ++ ++#define SDMA_STD_PRAGMA ((0 << SDMA_PRAGMA_BIT_RSV) | \ ++ (0 << SDMA_PRAGMA_BIT_PRECISE_INC) | \ ++ (0 << SDMA_PRAGMA_BIT_RST_ERROR_NO) | \ ++ (0 << SDMA_PRAGMA_BIT_PACK) | \ ++ (0 << SDMA_PRAGMA_BIT_INTEGER) | \ ++ (1 << SDMA_PRAGMA_BIT_SPECREAD) | \ ++ (1 << SDMA_PRAGMA_BIT_CW) | \ ++ (1 << SDMA_PRAGMA_BIT_RL)) ++ ++#define SDMA_PCI_PRAGMA ((0 << SDMA_PRAGMA_BIT_RSV) | \ ++ (0 << SDMA_PRAGMA_BIT_PRECISE_INC) | \ ++ (0 << SDMA_PRAGMA_BIT_RST_ERROR_NO) | \ ++ (0 << SDMA_PRAGMA_BIT_PACK) | \ ++ (1 << SDMA_PRAGMA_BIT_INTEGER) | \ ++ (1 << SDMA_PRAGMA_BIT_SPECREAD) | \ ++ (1 << SDMA_PRAGMA_BIT_CW) | \ ++ (1 << SDMA_PRAGMA_BIT_RL)) ++ ++#define SDMA_ATA_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_CRC16_DP_0_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_CRC16_DP_1_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_FEC_RX_BD_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_FEC_TX_BD_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_DP_0_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_DP_1_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_DP_2_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_DP_3_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_DP_BD_0_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_DP_BD_1_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_RX_BD_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_TX_BD_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_LPC_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_PCI_RX_PRAGMA SDMA_PCI_PRAGMA ++#define SDMA_PCI_TX_PRAGMA SDMA_PCI_PRAGMA ++ ++static inline void sdma_set_task_pragma(int task, int pragma) ++{ ++ u32 *fdt = &sdma.tdt[task].fdt; ++ *fdt = (*fdt & ~0xff) | pragma; ++} ++ ++static inline void sdma_set_task_auto_start(int task, int next_task) ++{ ++ u16 *tcr = &sdma.io->tcr[task]; ++ out_be16(tcr, (in_be16(tcr) & ~0xff) | 0x00c0 | next_task); ++} ++ ++#define SDMA_INITIATOR_ALWAYS 0 ++#define SDMA_INITIATOR_SCTMR_0 1 ++#define SDMA_INITIATOR_SCTMR_1 2 ++#define SDMA_INITIATOR_FEC_RX 3 ++#define SDMA_INITIATOR_FEC_TX 4 ++#define SDMA_INITIATOR_ATA_RX 5 ++#define SDMA_INITIATOR_ATA_TX 6 ++#define SDMA_INITIATOR_SCPCI_RX 7 ++#define SDMA_INITIATOR_SCPCI_TX 8 ++#define SDMA_INITIATOR_PSC3_RX 9 ++#define SDMA_INITIATOR_PSC3_TX 10 ++#define SDMA_INITIATOR_PSC2_RX 11 ++#define SDMA_INITIATOR_PSC2_TX 12 ++#define SDMA_INITIATOR_PSC1_RX 13 ++#define SDMA_INITIATOR_PSC1_TX 14 ++#define SDMA_INITIATOR_SCTMR_2 15 ++#define SDMA_INITIATOR_SCLPC 16 ++#define SDMA_INITIATOR_PSC5_RX 17 ++#define SDMA_INITIATOR_PSC5_TX 18 ++#define SDMA_INITIATOR_PSC4_RX 19 ++#define SDMA_INITIATOR_PSC4_TX 20 ++#define SDMA_INITIATOR_I2C2_RX 21 ++#define SDMA_INITIATOR_I2C2_TX 22 ++#define SDMA_INITIATOR_I2C1_RX 23 ++#define SDMA_INITIATOR_I2C1_TX 24 ++#define SDMA_INITIATOR_PSC6_RX 25 ++#define SDMA_INITIATOR_PSC6_TX 26 ++#define SDMA_INITIATOR_IRDA_RX 25 ++#define SDMA_INITIATOR_IRDA_TX 26 ++#define SDMA_INITIATOR_SCTMR_3 27 ++#define SDMA_INITIATOR_SCTMR_4 28 ++#define SDMA_INITIATOR_SCTMR_5 29 ++#define SDMA_INITIATOR_SCTMR_6 30 ++#define SDMA_INITIATOR_SCTMR_7 31 ++ ++#define SDMA_IPR_ALWAYS 7 ++#define SDMA_IPR_SCTMR_0 2 ++#define SDMA_IPR_SCTMR_1 2 ++#define SDMA_IPR_FEC_RX 6 ++#define SDMA_IPR_FEC_TX 5 ++#define SDMA_IPR_ATA_RX 4 ++#define SDMA_IPR_ATA_TX 3 ++#define SDMA_IPR_SCPCI_RX 2 ++#define SDMA_IPR_SCPCI_TX 2 ++#define SDMA_IPR_PSC3_RX 2 ++#define SDMA_IPR_PSC3_TX 2 ++#define SDMA_IPR_PSC2_RX 2 ++#define SDMA_IPR_PSC2_TX 2 ++#define SDMA_IPR_PSC1_RX 2 ++#define SDMA_IPR_PSC1_TX 2 ++#define SDMA_IPR_SCTMR_2 2 ++#define SDMA_IPR_SCLPC 2 ++#define SDMA_IPR_PSC5_RX 2 ++#define SDMA_IPR_PSC5_TX 2 ++#define SDMA_IPR_PSC4_RX 2 ++#define SDMA_IPR_PSC4_TX 2 ++#define SDMA_IPR_I2C2_RX 2 ++#define SDMA_IPR_I2C2_TX 2 ++#define SDMA_IPR_I2C1_RX 2 ++#define SDMA_IPR_I2C1_TX 2 ++#define SDMA_IPR_PSC6_RX 2 ++#define SDMA_IPR_PSC6_TX 2 ++#define SDMA_IPR_IRDA_RX 2 ++#define SDMA_IPR_IRDA_TX 2 ++#define SDMA_IPR_SCTMR_3 2 ++#define SDMA_IPR_SCTMR_4 2 ++#define SDMA_IPR_SCTMR_5 2 ++#define SDMA_IPR_SCTMR_6 2 ++#define SDMA_IPR_SCTMR_7 2 ++ ++extern struct sdma *sdma_alloc(int request_queue_size); ++extern void sdma_free(struct sdma *sdma_struct); ++extern int sdma_load_task(u32 *task_image); ++extern void *sdma_sram_alloc(int size, int alignment, u32 *dma_handle); ++extern void sdma_init_bd(struct sdma *s); ++extern void sdma_init_bd2(struct sdma *s); ++ ++#define FIELD_OFFSET(s,f) ((unsigned long)(&(((struct s*)0)->f))) ++ ++#endif /* __BESTCOMM_BESTCOMM_H__ */ +diff --git a/arch/ppc/syslib/bestcomm/fec.c b/arch/ppc/syslib/bestcomm/fec.c +new file mode 100644 +index 0000000..8756856 +--- /dev/null ++++ b/arch/ppc/syslib/bestcomm/fec.c +@@ -0,0 +1,174 @@ ++/* ++ * arch/ppc/syslib/bestcomm/fec.c ++ * ++ * Driver for MPC52xx processor BestComm FEC controller ++ * ++ * Author: Dale Farnsworth ++ * ++ * 2003-2004 (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. ++ * ++ * HISTORY: ++ * ++ * 2005-08-14 Converted to platform driver by ++ * Andrey Volkov , Varma Electronics Oy ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "bestcomm.h" ++#include "fec.h" ++ ++/* ++ * Initialize FEC receive task. ++ * Returns task number of FEC receive task. ++ * Returns -1 on failure ++ */ ++int sdma_fec_rx_init(struct sdma *s, phys_addr_t fifo, int maxbufsize) ++{ ++ struct sdma_fec_rx_var *var; ++ struct sdma_fec_rx_inc *inc; ++ ++ static int tasknum = -1; ++ static struct sdma_bd *bd = 0; ++ static u32 bd_pa; ++ ++ if (tasknum < 0) { ++ tasknum = sdma_load_task(sdma_fec_rx_task); ++ if (tasknum < 0) ++ return tasknum; ++ } ++ ++ if (!bd) ++ bd = (struct sdma_bd *)sdma_sram_alloc(sizeof(*bd) * s->num_bd, ++ SDMA_BD_ALIGN, &bd_pa); ++ if (!bd) ++ return -ENOMEM; ++ ++ sdma_disable_task(tasknum); ++ ++ s->tasknum = tasknum; ++ s->bd = bd; ++ s->flags = SDMA_FLAGS_NONE; ++ s->index = 0; ++ s->outdex = 0; ++ memset(bd, 0, sizeof(*bd) * s->num_bd); ++ ++ var = (struct sdma_fec_rx_var *)sdma_task_var(tasknum); ++ var->enable = sdma_io_pa(&sdma.io->tcr[tasknum]); ++ var->fifo = fifo; ++ var->bd_base = bd_pa; ++ var->bd_last = bd_pa + (s->num_bd - 1)*sizeof(struct sdma_bd); ++ var->bd_start = bd_pa; ++ var->buffer_size = maxbufsize; ++ ++ /* These are constants, they should have been in the image file */ ++ inc = (struct sdma_fec_rx_inc *)sdma_task_inc(tasknum); ++ inc->incr_bytes = -(s16)sizeof(u32); ++ inc->incr_dst = sizeof(u32); ++ inc->incr_dst_ma = sizeof(u8); ++ ++ sdma_set_task_pragma(tasknum, SDMA_FEC_RX_BD_PRAGMA); ++ sdma_set_task_auto_start(tasknum, tasknum); ++ ++ /* clear pending interrupt bits */ ++ out_be32(&sdma.io->IntPend, 1<ipr[SDMA_INITIATOR_FEC_RX], SDMA_IPR_FEC_RX); ++ ++ return tasknum; ++} ++ ++/* ++ * Return 2nd to last DRD ++ * This is an ugly hack, but at least it's only done once at initialization ++ */ ++static u32 *self_modified_drd(int tasknum) ++{ ++ u32 *desc; ++ int num_descs; ++ int drd_count; ++ int i; ++ ++ num_descs = sdma_task_num_descs(tasknum); ++ desc = sdma_task_desc(tasknum) + num_descs - 1; ++ drd_count = 0; ++ for (i=0; inum_bd, ++ SDMA_BD_ALIGN, &bd_pa); ++ if (!bd) ++ return -ENOMEM; ++ ++ sdma_disable_task(tasknum); ++ ++ s->tasknum = tasknum; ++ s->bd = bd; ++ s->flags = SDMA_FLAGS_ENABLE_TASK; ++ s->index = 0; ++ s->outdex = 0; ++ memset(bd, 0, sizeof(*bd) * s->num_bd); ++ ++ var = (struct sdma_fec_tx_var *)sdma_task_var(tasknum); ++ var->DRD = sdma_sram_pa(self_modified_drd(tasknum)); ++ var->fifo = fifo; ++ var->enable = sdma_io_pa(&sdma.io->tcr[tasknum]); ++ var->bd_base = bd_pa; ++ var->bd_last = bd_pa + (s->num_bd - 1)*sizeof(struct sdma_bd); ++ var->bd_start = bd_pa; ++ ++ /* These are constants, they should have been in the image file */ ++ inc = (struct sdma_fec_tx_inc *)sdma_task_inc(tasknum); ++ inc->incr_bytes = -(s16)sizeof(u32); ++ inc->incr_src = sizeof(u32); ++ inc->incr_src_ma = sizeof(u8); ++ ++ sdma_set_task_pragma(tasknum, SDMA_FEC_TX_BD_PRAGMA); ++ sdma_set_task_auto_start(tasknum, tasknum); ++ ++ /* clear pending interrupt bits */ ++ out_be32(&sdma.io->IntPend, 1<ipr[SDMA_INITIATOR_FEC_TX], SDMA_IPR_FEC_TX); ++ ++ return tasknum; ++} ++ ++EXPORT_SYMBOL(sdma_fec_rx_init); ++EXPORT_SYMBOL(sdma_fec_tx_init); +diff --git a/arch/ppc/syslib/bestcomm/fec.h b/arch/ppc/syslib/bestcomm/fec.h +new file mode 100644 +index 0000000..e3abc0f +--- /dev/null ++++ b/arch/ppc/syslib/bestcomm/fec.h +@@ -0,0 +1,71 @@ ++/* ++ * arch/ppc/syslib/bestcomm/fec.h ++ * ++ * Driver for MPC52xx processor BestComm FEC controller ++ * ++ * Author: Dale Farnsworth ++ * ++ * 2003-2004 (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. ++ * ++ * HISTORY: ++ * ++ * 2005-08-14 Converted to platform driver by ++ * Andrey Volkov , Varma Electronics Oy ++ */ ++ ++#ifndef __BESTCOMM_FEC_H__ ++#define __BESTCOMM_FEC_H__ ++ ++ ++/* rx task vars that need to be set before enabling the task */ ++struct sdma_fec_rx_var { ++ u32 enable; /* (u16*) address of task's control register */ ++ u32 fifo; /* (u32*) address of fec's fifo */ ++ u32 bd_base; /* (struct sdma_bd*) beginning of ring buffer */ ++ u32 bd_last; /* (struct sdma_bd*) end of ring buffer */ ++ u32 bd_start; /* (struct sdma_bd*) current bd */ ++ u32 buffer_size; /* size of receive buffer */ ++}; ++ ++/* rx task incs that need to be set before enabling the task */ ++struct sdma_fec_rx_inc { ++ u16 pad0; ++ s16 incr_bytes; ++ u16 pad1; ++ s16 incr_dst; ++ u16 pad2; ++ s16 incr_dst_ma; ++}; ++ ++/* tx task vars that need to be set before enabling the task */ ++struct sdma_fec_tx_var { ++ u32 DRD; /* (u32*) address of self-modified DRD */ ++ u32 fifo; /* (u32*) address of fec's fifo */ ++ u32 enable; /* (u16*) address of task's control register */ ++ u32 bd_base; /* (struct sdma_bd*) beginning of ring buffer */ ++ u32 bd_last; /* (struct sdma_bd*) end of ring buffer */ ++ u32 bd_start; /* (struct sdma_bd*) current bd */ ++ u32 buffer_size; /* set by uCode for each packet */ ++}; ++ ++/* tx task incs that need to be set before enabling the task */ ++struct sdma_fec_tx_inc { ++ u16 pad0; ++ s16 incr_bytes; ++ u16 pad1; ++ s16 incr_src; ++ u16 pad2; ++ s16 incr_src_ma; ++}; ++ ++extern int sdma_fec_rx_init(struct sdma *s, phys_addr_t fifo, int maxbufsize); ++extern int sdma_fec_tx_init(struct sdma *s, phys_addr_t fifo); ++ ++extern u32 sdma_fec_rx_task[]; ++extern u32 sdma_fec_tx_task[]; ++ ++ ++#endif /* __BESTCOMM_FEC_H__ */ +diff --git a/arch/ppc/syslib/bestcomm/sdma_fec_rx_task.c b/arch/ppc/syslib/bestcomm/sdma_fec_rx_task.c +new file mode 100644 +index 0000000..511b036 +--- /dev/null ++++ b/arch/ppc/syslib/bestcomm/sdma_fec_rx_task.c +@@ -0,0 +1,71 @@ ++/* ++ * sdma_fec_rx_task.c ++ * ++ * Automatically created based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex ++ * on Tue Mar 22 11:19:38 2005 GMT ++ */ ++ ++#include ++ ++/* ++ * The header consists of the following fields: ++ * uint32_t magic; ++ * uint8_t desc_size; ++ * uint8_t var_size; ++ * uint8_t inc_size; ++ * uint8_t first_var; ++ * uint8_t reserved[8]; ++ * ++ * The size fields contain the number of 32-bit words. ++*/ ++ ++uint32_t sdma_fec_rx_task[] = { ++ /* header */ ++ 0x4243544b, ++ 0x18060709, ++ 0x00000000, ++ 0x00000000, ++ ++ /* Task descriptors */ ++ 0x808220e3, /* LCD: idx0 = var1, idx1 = var4; idx1 <= var3; idx0 += inc4, idx1 += inc3 */ ++ 0x10601010, /* DRD1A: var4 = var2; FN=0 MORE init=3 WS=0 RS=0 */ ++ 0xb8800264, /* LCD: idx2 = *idx1, idx3 = var0; idx2 < var9; idx2 += inc4, idx3 += inc4 */ ++ 0x10001308, /* DRD1A: var4 = idx1; FN=0 MORE init=0 WS=0 RS=0 */ ++ 0x60140002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */ ++ 0x0cccfcca, /* DRD2B1: *idx3 = EU3(); EU3(*idx3,var10) */ ++ 0x80004000, /* LCDEXT: idx2 = 0x00000000; ; */ ++ 0xb8c58029, /* LCD: idx3 = *(idx1 + var00000015); idx3 once var0; idx3 += inc5 */ ++ 0x60000002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=0 RS=0 */ ++ 0x088cf8cc, /* DRD2B1: idx2 = EU3(); EU3(idx3,var12) */ ++ 0x991982f2, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var11; idx2 += inc6, idx3 += inc2 */ ++ 0x006acf80, /* DRD1A: *idx3 = *idx0; FN=0 init=3 WS=1 RS=1 */ ++ 0x80004000, /* LCDEXT: idx2 = 0x00000000; ; */ ++ 0x9999802d, /* LCD: idx3 = idx3; idx3 once var0; idx3 += inc5 */ ++ 0x70000002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */ ++ 0x034cfc4e, /* DRD2B1: var13 = EU3(); EU3(*idx1,var14) */ ++ 0x00008868, /* DRD1A: idx2 = var13; FN=0 init=0 WS=0 RS=0 */ ++ 0x99198341, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var13; idx2 += inc0, idx3 += inc1 */ ++ 0x007ecf80, /* DRD1A: *idx3 = *idx0; FN=0 init=3 WS=3 RS=3 */ ++ 0x99198272, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var9; idx2 += inc6, idx3 += inc2 */ ++ 0x046acf80, /* DRD1A: *idx3 = *idx0; FN=0 INT init=3 WS=1 RS=1 */ ++ 0x9819002d, /* LCD: idx2 = idx0; idx2 once var0; idx2 += inc5 */ ++ 0x0060c790, /* DRD1A: *idx1 = *idx2; FN=0 init=3 WS=0 RS=0 */ ++ 0x000001f8, /* NOP */ ++ ++ /* VAR[9]-VAR[14] */ ++ 0x40000000, ++ 0x7fff7fff, ++ 0x00000000, ++ 0x00000003, ++ 0x40000008, ++ 0x43ffffff, ++ ++ /* INC[0]-INC[6] */ ++ 0x40000000, ++ 0xe0000000, ++ 0xe0000000, ++ 0xa0000008, ++ 0x20000000, ++ 0x00000000, ++ 0x4000ffff, ++}; +diff --git a/arch/ppc/syslib/bestcomm/sdma_fec_tx_task.c b/arch/ppc/syslib/bestcomm/sdma_fec_tx_task.c +new file mode 100644 +index 0000000..d8d7fd3 +--- /dev/null ++++ b/arch/ppc/syslib/bestcomm/sdma_fec_tx_task.c +@@ -0,0 +1,84 @@ ++/* ++ * sdma_fec_tx_task.c ++ * ++ * Automatically created based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex ++ * on Tue Mar 22 11:19:29 2005 GMT ++ */ ++ ++#include ++ ++/* ++ * The header consists of the following fields: ++ * uint32_t magic; ++ * uint8_t desc_size; ++ * uint8_t var_size; ++ * uint8_t inc_size; ++ * uint8_t first_var; ++ * uint8_t reserved[8]; ++ * ++ * The size fields contain the number of 32-bit words. ++*/ ++ ++uint32_t sdma_fec_tx_task[] = { ++ /* header */ ++ 0x4243544b, ++ 0x2407070d, ++ 0x00000000, ++ 0x00000000, ++ ++ /* Task descriptors */ ++ 0x8018001b, /* LCD: idx0 = var0; idx0 <= var0; idx0 += inc3 */ ++ 0x60000005, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */ ++ 0x01ccfc0d, /* DRD2B1: var7 = EU3(); EU3(*idx0,var13) */ ++ 0x8082a123, /* LCD: idx0 = var1, idx1 = var5; idx1 <= var4; idx0 += inc4, idx1 += inc3 */ ++ 0x10801418, /* DRD1A: var5 = var3; FN=0 MORE init=4 WS=0 RS=0 */ ++ 0xf88103a4, /* LCDEXT: idx2 = *idx1, idx3 = var2; idx2 < var14; idx2 += inc4, idx3 += inc4 */ ++ 0x801a6024, /* LCD: idx4 = var0; ; idx4 += inc4 */ ++ 0x10001708, /* DRD1A: var5 = idx1; FN=0 MORE init=0 WS=0 RS=0 */ ++ 0x60140002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */ ++ 0x0cccfccf, /* DRD2B1: *idx3 = EU3(); EU3(*idx3,var15) */ ++ 0x991a002c, /* LCD: idx2 = idx2, idx3 = idx4; idx2 once var0; idx2 += inc5, idx3 += inc4 */ ++ 0x70000002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */ ++ 0x024cfc4d, /* DRD2B1: var9 = EU3(); EU3(*idx1,var13) */ ++ 0x60000003, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=3 EXT init=0 WS=0 RS=0 */ ++ 0x0cccf247, /* DRD2B1: *idx3 = EU3(); EU3(var9,var7) */ ++ 0x80004000, /* LCDEXT: idx2 = 0x00000000; ; */ ++ 0xb8c80029, /* LCD: idx3 = *(idx1 + var0000001a); idx3 once var0; idx3 += inc5 */ ++ 0x70000002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */ ++ 0x088cf8d1, /* DRD2B1: idx2 = EU3(); EU3(idx3,var17) */ ++ 0x00002f10, /* DRD1A: var11 = idx2; FN=0 init=0 WS=0 RS=0 */ ++ 0x99198432, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var16; idx2 += inc6, idx3 += inc2 */ ++ 0x008ac398, /* DRD1A: *idx0 = *idx3; FN=0 init=4 WS=1 RS=1 */ ++ 0x80004000, /* LCDEXT: idx2 = 0x00000000; ; */ ++ 0x9999802d, /* LCD: idx3 = idx3; idx3 once var0; idx3 += inc5 */ ++ 0x70000002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */ ++ 0x048cfc53, /* DRD2B1: var18 = EU3(); EU3(*idx1,var19) */ ++ 0x60000008, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=8 EXT init=0 WS=0 RS=0 */ ++ 0x088cf48b, /* DRD2B1: idx2 = EU3(); EU3(var18,var11) */ ++ 0x99198481, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var18; idx2 += inc0, idx3 += inc1 */ ++ 0x009ec398, /* DRD1A: *idx0 = *idx3; FN=0 init=4 WS=3 RS=3 */ ++ 0x991983b2, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var14; idx2 += inc6, idx3 += inc2 */ ++ 0x088ac398, /* DRD1A: *idx0 = *idx3; FN=0 TFD init=4 WS=1 RS=1 */ ++ 0x9919002d, /* LCD: idx2 = idx2; idx2 once var0; idx2 += inc5 */ ++ 0x60000005, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */ ++ 0x0c4cf88e, /* DRD2B1: *idx1 = EU3(); EU3(idx2,var14) */ ++ 0x000001f8, /* NOP */ ++ ++ /* VAR[13]-VAR[19] */ ++ 0x0c000000, ++ 0x40000000, ++ 0x7fff7fff, ++ 0x00000000, ++ 0x00000003, ++ 0x40000004, ++ 0x43ffffff, ++ ++ /* INC[0]-INC[6] */ ++ 0x40000000, ++ 0xe0000000, ++ 0xe0000000, ++ 0xa0000008, ++ 0x20000000, ++ 0x00000000, ++ 0x4000ffff, ++}; +diff --git a/arch/ppc/syslib/mpc52xx_devices.c b/arch/ppc/syslib/mpc52xx_devices.c +index 7487539..abe6161 100644 +--- a/arch/ppc/syslib/mpc52xx_devices.c ++++ b/arch/ppc/syslib/mpc52xx_devices.c +@@ -33,6 +33,28 @@ static struct fsl_i2c_platform_data mpc52xx_fsl_i2c_pdata = { + possibly using IORESOURCE_DMA. But that's when BestComm is ready ... */ + + struct platform_device ppc_sys_platform_devices[] = { ++ [MPC52xx_SDMA] = { ++ .name = "mpc52xx-sdma", ++ .id = -1, ++ .num_resources = 3, ++ .resource = (struct resource[]) { ++ { ++ .start = 0x1200, ++ .end = 0x12ff, ++ .flags = IORESOURCE_MEM, ++ }, ++ { ++ .start = 0x8000, ++ .end = 0xbfff, ++ .flags = IORESOURCE_MEM, ++ }, ++ { ++ .start = MPC52xx_SDMA_IRQ, ++ .end = MPC52xx_SDMA_IRQ, ++ .flags = IORESOURCE_IRQ, ++ }, ++ }, ++ }, + [MPC52xx_MSCAN1] = { + .name = "mpc52xx-mscan", + .id = 0, +diff --git a/arch/ppc/syslib/mpc52xx_sys.c b/arch/ppc/syslib/mpc52xx_sys.c +index b4e6f97..a74b19c 100644 +--- a/arch/ppc/syslib/mpc52xx_sys.c ++++ b/arch/ppc/syslib/mpc52xx_sys.c +@@ -19,10 +19,10 @@ struct ppc_sys_spec ppc_sys_specs[] = { + .ppc_sys_name = "5200", + .mask = 0xffff0000, + .value = 0x80110000, +- .num_devices = 15, ++ .num_devices = MPC52xx_NUM_DEVICES, + .device_list = (enum ppc_sys_devices[]) + { +- MPC52xx_MSCAN1, MPC52xx_MSCAN2, MPC52xx_SPI, ++ MPC52xx_SDMA, MPC52xx_MSCAN1, MPC52xx_MSCAN2, MPC52xx_SPI, + MPC52xx_USB, MPC52xx_BDLC, MPC52xx_PSC1, MPC52xx_PSC2, + MPC52xx_PSC3, MPC52xx_PSC4, MPC52xx_PSC5, MPC52xx_PSC6, + MPC52xx_FEC, MPC52xx_ATA, MPC52xx_I2C1, MPC52xx_I2C2, +diff --git a/include/asm-ppc/mpc52xx.h b/include/asm-ppc/mpc52xx.h +index d9d21aa..4856b74 100644 +--- a/include/asm-ppc/mpc52xx.h ++++ b/include/asm-ppc/mpc52xx.h +@@ -34,6 +34,8 @@ struct pt_regs; + /* ======================================================================== */ + + enum ppc_sys_devices { ++ MPC52xx_SDMA, /* Must be first device to probe, ++ else FEC/ATA will failed */ + MPC52xx_MSCAN1, + MPC52xx_MSCAN2, + MPC52xx_SPI, +-- +1.4.4.2 + diff --git a/debian/patches/features/powerpc/efika/0007-Add-MPC5200-ethernet-driver.diff b/debian/patches/features/powerpc/efika/0020-Fec-MPC5200-eth-driver.txt similarity index 92% rename from debian/patches/features/powerpc/efika/0007-Add-MPC5200-ethernet-driver.diff rename to debian/patches/features/powerpc/efika/0020-Fec-MPC5200-eth-driver.txt index 0d2818893..6c9ab0ebe 100644 --- a/debian/patches/features/powerpc/efika/0007-Add-MPC5200-ethernet-driver.diff +++ b/debian/patches/features/powerpc/efika/0020-Fec-MPC5200-eth-driver.txt @@ -1,34 +1,37 @@ -From 0eae8b0fed7d8342c027e15d2a6d52eae10366e1 Mon Sep 17 00:00:00 2001 -From: Nicolas DET -Date: Fri, 24 Nov 2006 13:09:04 +0100 -Subject: [PATCH] Add MPC5200 ethernet driver +From 6b6e09cca4346ea737db427d568843034eb348fa Mon Sep 17 00:00:00 2001 +From: Andrey Volkov +Date: Fri, 18 Aug 2006 10:02:29 -0600 +Subject: [PATCH] [PATCH 02/02] Fec MPC5200 eth driver -Signed-off-by: Nicolas DET +Second part. Contain only FEC parts. +Depended on previous bestcomm patch. + +Signed-Off-By: Andrey Volkov --- drivers/net/Kconfig | 1 + drivers/net/Makefile | 1 + - drivers/net/fec_mpc52xx/Kconfig | 22 + + drivers/net/fec_mpc52xx/Kconfig | 23 ++ drivers/net/fec_mpc52xx/Makefile | 2 + - drivers/net/fec_mpc52xx/fec.c | 817 +++++++++++++++++++++++++++++++++++++ - drivers/net/fec_mpc52xx/fec.h | 308 ++++++++++++++ - drivers/net/fec_mpc52xx/fec_phy.c | 532 ++++++++++++++++++++++++ + drivers/net/fec_mpc52xx/fec.c | 768 +++++++++++++++++++++++++++++++++++++ + drivers/net/fec_mpc52xx/fec.h | 308 +++++++++++++++ + drivers/net/fec_mpc52xx/fec_phy.c | 526 +++++++++++++++++++++++++ drivers/net/fec_mpc52xx/fec_phy.h | 73 ++++ - 8 files changed, 1756 insertions(+), 0 deletions(-) + 8 files changed, 1702 insertions(+), 0 deletions(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig -index 6e863aa..c0bf347 100644 +index 8aa8dd0..0658e92 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig -@@ -1892,6 +1892,7 @@ config NE_H8300 +@@ -1902,6 +1902,7 @@ config NE_H8300 + controller on the Renesas H8/300 processor. source "drivers/net/fec_8xx/Kconfig" - source "drivers/net/fs_enet/Kconfig" +source "drivers/net/fec_mpc52xx/Kconfig" + source "drivers/net/fs_enet/Kconfig" endmenu - diff --git a/drivers/net/Makefile b/drivers/net/Makefile -index f270bc4..a39a931 100644 +index 4c0d4e5..e6f903d 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -196,6 +196,7 @@ obj-$(CONFIG_SMC91X) += smc91x.o @@ -37,27 +40,28 @@ index f270bc4..a39a931 100644 obj-$(CONFIG_FEC_8XX) += fec_8xx/ +obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx/ - obj-$(CONFIG_ARM) += arm/ - obj-$(CONFIG_DEV_APPLETALK) += appletalk/ + obj-$(CONFIG_MACB) += macb.o + diff --git a/drivers/net/fec_mpc52xx/Kconfig b/drivers/net/fec_mpc52xx/Kconfig new file mode 100644 -index 0000000..dc3fee6 +index 0000000..098c3fa --- /dev/null +++ b/drivers/net/fec_mpc52xx/Kconfig -@@ -0,0 +1,22 @@ +@@ -0,0 +1,23 @@ +menu "MPC5200 Networking Options" -+ depends (PPC_CHRP || PPC_MPC52xx) && NET_ETHERNET ++ depends PPC_MPC52xx && NET_ETHERNET + +config FEC_MPC52xx + bool "FEC Ethernet" + depends on NET_ETHERNET ++ select PPC_BESTCOMM + select CRC32 + ---help--- + This option enables support for the MPC5200's on-chip + Fast Ethernet Controller + +config USE_MDIO -+ bool "Use external Ethernet MII PHY" ++ bool " Use external Ethernet MII PHY" + select MII + depends FEC_MPC52xx + ---help--- @@ -77,10 +81,10 @@ index 0000000..b8ae05c +obj-$(CONFIG_USE_MDIO) += fec_phy.o diff --git a/drivers/net/fec_mpc52xx/fec.c b/drivers/net/fec_mpc52xx/fec.c new file mode 100644 -index 0000000..5591bb7 +index 0000000..b5f1559 --- /dev/null +++ b/drivers/net/fec_mpc52xx/fec.c -@@ -0,0 +1,817 @@ +@@ -0,0 +1,768 @@ +/* + * drivers/net/fec_mpc52xx/fec.c + * @@ -110,40 +114,20 @@ index 0000000..5591bb7 + +#include +#include ++#include +#include -+#include -+#include + -+#ifdef CONFIG_PPC_EFIKA -+#include -+#else +#include +#include -+#endif -+ -+/******************/ -+/******************/ -+static unsigned long get_ipbfreq(void) -+{ -+#ifdef CONFIG_PPC_EFIKA -+ return (132*1000*1000); -+#else -+ bd_t *bd = (bd_t *)&__res; -+ return bd->bi_ipbfreq -+#endif -+} -+ -+/******************/ -+/******************/ + +#include "fec_phy.h" +#include "fec.h" + +#define DRIVER_NAME "mpc52xx-fec" + -+static irqreturn_t fec_interrupt(int, void *); -+static irqreturn_t fec_rx_interrupt(int, void *); -+static irqreturn_t fec_tx_interrupt(int, void *); ++static irqreturn_t fec_interrupt(int, void *, struct pt_regs *); ++static irqreturn_t fec_rx_interrupt(int, void *, struct pt_regs *); ++static irqreturn_t fec_tx_interrupt(int, void *, struct pt_regs *); +static struct net_device_stats *fec_get_stats(struct net_device *); +static void fec_set_multicast_list(struct net_device *dev); +static void fec_reinit(struct net_device *dev); @@ -336,7 +320,7 @@ index 0000000..5591bb7 + +/* This handles BestComm transmit task interrupts + */ -+static irqreturn_t fec_tx_interrupt(int irq, void *dev_id) ++static irqreturn_t fec_tx_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct fec_priv *priv = (struct fec_priv *)dev->priv; @@ -362,7 +346,7 @@ index 0000000..5591bb7 + return IRQ_HANDLED; +} + -+static irqreturn_t fec_rx_interrupt(int irq, void *dev_id) ++static irqreturn_t fec_rx_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct fec_priv *priv = (struct fec_priv *)dev->priv; @@ -419,7 +403,7 @@ index 0000000..5591bb7 + return IRQ_HANDLED; +} + -+static irqreturn_t fec_interrupt(int irq, void *dev_id) ++static irqreturn_t fec_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct fec_priv *priv = (struct fec_priv *)dev->priv; @@ -427,24 +411,17 @@ index 0000000..5591bb7 + int ievent; + + ievent = in_be32(&fec->ievent); -+ if (!ievent) -+ return IRQ_NONE; -+ + out_be32(&fec->ievent, ievent); /* clear pending events */ + + if (ievent & (FEC_IEVENT_RFIFO_ERROR | FEC_IEVENT_XFIFO_ERROR)) { -+ if ( net_ratelimit() ) -+ { -+ if (ievent & FEC_IEVENT_RFIFO_ERROR) -+ printk(KERN_WARNING "FEC_IEVENT_RFIFO_ERROR (%8.8x)\n", ievent); -+ if (ievent & FEC_IEVENT_XFIFO_ERROR) -+ printk(KERN_WARNING "FEC_IEVENT_XFIFO_ERROR (%8.8x)\n", ievent); -+ } ++ if (ievent & FEC_IEVENT_RFIFO_ERROR) ++ printk(KERN_WARNING "FEC_IEVENT_RFIFO_ERROR\n"); ++ if (ievent & FEC_IEVENT_XFIFO_ERROR) ++ printk(KERN_WARNING "FEC_IEVENT_XFIFO_ERROR\n"); + fec_reinit(dev); + } + else if (ievent & FEC_IEVENT_MII) + fec_mii(dev); -+ + return IRQ_HANDLED; +} + @@ -605,7 +582,8 @@ index 0000000..5591bb7 +{ + struct fec_priv *priv = (struct fec_priv *)dev->priv; + struct mpc52xx_fec *fec = priv->fec; -+ ++ bd_t *bd = (bd_t *) &__res; ++ + out_be32(&fec->op_pause, 0x00010020); + out_be32(&fec->rfifo_cntrl, 0x0f000000); + out_be32(&fec->rfifo_alarm, 0x0000030c); @@ -616,7 +594,7 @@ index 0000000..5591bb7 + out_be32(&fec->iaddr1, 0x00000000); /* No individual filter */ + out_be32(&fec->iaddr2, 0x00000000); /* No individual filter */ + -+ priv->phy_speed = ((get_ipbfreq() >> 20) / 5) << 1; ++ priv->phy_speed = ((bd->bi_ipbfreq >> 20) / 5) << 1; + + fec_restart(dev, 0); /* always use half duplex mode only */ + /* @@ -626,12 +604,13 @@ index 0000000..5591bb7 + fec_update_stat(dev); +} + -+static void fec_update_stat(struct net_device *); ++ +static void fec_reinit(struct net_device *dev) +{ + struct fec_priv *priv = (struct fec_priv *)dev->priv; + struct mpc52xx_fec *fec = priv->fec; -+ ++ static void fec_update_stat(struct net_device *); ++ + netif_stop_queue(dev); + out_be32(&fec->imask, 0x0); + @@ -660,31 +639,33 @@ index 0000000..5591bb7 +/* ======================================================================== */ + +static int __devinit -+mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match) ++mpc52xx_fec_probe(struct device *dev) +{ + int ret; -+ int rv; ++ struct platform_device *pdev = to_platform_device(dev); + struct net_device *ndev; + struct fec_priv *priv = NULL; -+ struct resource mem; ++ struct resource *mem; + ++ volatile int dbg=0; ++ while(dbg) ++ __asm("nop"); + /* Reserve FEC control zone */ -+ rv = of_address_to_resource(op->node, 0, &mem); -+ if (rv) { -+ printk(KERN_ERR DRIVER_NAME ": " -+ "Error while parsing device node resource\n" ); -+ return rv; ++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if ((mem->end - mem->start + 1) != sizeof(struct mpc52xx_fec)) { ++ printk(KERN_ERR DRIVER_NAME ++ " - invalid resource size (%lx != %x), check mpc52xx_devices.c\n", ++ mem->end - mem->start + 1, sizeof(struct mpc52xx_fec)); ++ return -EINVAL; + } + -+ if (!request_mem_region(mem.start, sizeof(struct mpc52xx_fec), ++ if (!request_mem_region(mem->start, sizeof(struct mpc52xx_fec), + DRIVER_NAME)) + return -EBUSY; + + /* Get the ether ndev & it's private zone */ + ndev = alloc_etherdev(sizeof(struct fec_priv)); + if (!ndev) { -+ printk(KERN_ERR DRIVER_NAME ": " -+ "Can not allocate the ethernet device\n" ); + ret = -ENOMEM; + goto probe_error; + } @@ -702,7 +683,7 @@ index 0000000..5591bb7 + ndev->tx_timeout = fec_tx_timeout; + ndev->watchdog_timeo = FEC_WATCHDOG_TIMEOUT; + ndev->flags &= ~IFF_RUNNING; -+ ndev->base_addr = mem.start; ++ ndev->base_addr = mem->start; + + priv->rx_fifo = ndev->base_addr + FIELD_OFFSET(mpc52xx_fec,rfifo_data); + priv->tx_fifo = ndev->base_addr + FIELD_OFFSET(mpc52xx_fec,tfifo_data); @@ -712,27 +693,18 @@ index 0000000..5591bb7 + + /* ioremap the zones */ + priv->fec = (struct mpc52xx_fec *) -+ ioremap(mem.start, sizeof(struct mpc52xx_fec)); ++ ioremap(mem->start, sizeof(struct mpc52xx_fec)); + + if (!priv->fec) { -+ printk(KERN_ERR DRIVER_NAME ": " -+ "Can not remap IO memory at 0x%8.8x\n", mem.start ); + ret = -ENOMEM; + goto probe_error; + } + + /* SDMA init */ -+#ifdef CONFIG_PPC_EFIKA -+ priv->rx_sdma = sdma_fex_rx_preinit(FEC_RX_NUM_BD); -+ priv->tx_sdma = sdma_fex_tx_preinit(FEC_TX_NUM_BD); -+#else + priv->rx_sdma = sdma_alloc(FEC_RX_NUM_BD); + priv->tx_sdma = sdma_alloc(FEC_TX_NUM_BD); -+#endif + + if (!priv->rx_sdma || !priv->tx_sdma) { -+ printk(KERN_ERR DRIVER_NAME ": " -+ "Can not init SDMA tasks\n" ); + ret = -ENOMEM; + goto probe_error; + } @@ -746,10 +718,8 @@ index 0000000..5591bb7 + goto probe_error; + + /* Get the IRQ we need one by one */ -+ /* Control */ -+ -+ ndev->irq = irq_of_parse_and_map(op->node, 0); -+ ++ /* Control */ ++ ndev->irq = platform_get_irq(pdev, 0); + if (request_irq(ndev->irq, &fec_interrupt, SA_INTERRUPT, + DRIVER_NAME "_ctrl", ndev)) { + printk(KERN_ERR DRIVER_NAME ": ctrl interrupt request failed\n"); @@ -758,7 +728,7 @@ index 0000000..5591bb7 + goto probe_error; + } + -+ /* RX */ ++ /* RX */ + priv->r_irq = sdma_irq(priv->rx_sdma); + if (request_irq(priv->r_irq, &fec_rx_interrupt, SA_INTERRUPT, + DRIVER_NAME "_rx", ndev)) { @@ -768,7 +738,7 @@ index 0000000..5591bb7 + goto probe_error; + } + -+ /* TX */ ++ /* TX */ + priv->t_irq = sdma_irq(priv->tx_sdma); + if (request_irq(priv->t_irq, &fec_tx_interrupt, SA_INTERRUPT, + DRIVER_NAME "_tx", ndev)) { @@ -796,11 +766,12 @@ index 0000000..5591bb7 + fec_mii_init(ndev); + + /* We're done ! */ -+ dev_set_drvdata(&op->dev, ndev); ++ dev_set_drvdata(dev, ndev); + + return 0; + -+ /* Errorx handling - free everything that might be allocated */ ++ ++ /* Error handling - free everything that might be allocated */ +probe_error: + + if (ndev) { @@ -816,18 +787,18 @@ index 0000000..5591bb7 + free_netdev(ndev); + } + -+ release_mem_region(mem.start, sizeof(struct mpc52xx_fec)); ++ release_mem_region(mem->start, sizeof(struct mpc52xx_fec)); + + return ret; +} + +static int -+mpc52xx_fec_remove(struct of_device *op) ++mpc52xx_fec_remove(struct device *dev) +{ + struct net_device *ndev; + struct fec_priv *priv; + -+ ndev = (struct net_device *) dev_get_drvdata(&op->dev); ++ ndev = (struct net_device *) dev_get_drvdata(dev); + if (!ndev) + return 0; + priv = (struct fec_priv *) ndev->priv; @@ -844,35 +815,19 @@ index 0000000..5591bb7 + + free_netdev(ndev); + -+ dev_set_drvdata(&op->dev, NULL); ++ dev_set_drvdata(dev, NULL); + return 0; +} + -+static struct of_device_id mpc52xx_fec_of_match[] = { -+ { -+ .compatible = "mpc5200-ethernet", -+ }, -+ { -+ .compatible = "mpc52xx-fec", -+ }, -+ {}, -+}; -+ -+ -+static struct of_platform_driver mpc52xx_fec_driver = { ++static struct device_driver mpc52xx_fec_driver = { + .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ .match_table = mpc52xx_fec_of_match, ++ .bus = &platform_bus_type, + .probe = mpc52xx_fec_probe, + .remove = mpc52xx_fec_remove, +#ifdef CONFIG_PM +/* .suspend = mpc52xx_fec_suspend, TODO */ +/* .resume = mpc52xx_fec_resume, TODO */ +#endif -+ .driver = { -+ .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ }, +}; + +/* ======================================================================== */ @@ -882,13 +837,13 @@ index 0000000..5591bb7 +static int __init +mpc52xx_fec_init(void) +{ -+ return of_register_platform_driver(&mpc52xx_fec_driver); ++ return driver_register(&mpc52xx_fec_driver); +} + +static void __exit +mpc52xx_fec_exit(void) +{ -+ of_unregister_platform_driver(&mpc52xx_fec_driver); ++ driver_unregister(&mpc52xx_fec_driver); +} + + @@ -1214,10 +1169,10 @@ index 0000000..f9eed36 +#endif /* __DRIVERS_NET_MPC52XX_FEC_H__ */ diff --git a/drivers/net/fec_mpc52xx/fec_phy.c b/drivers/net/fec_mpc52xx/fec_phy.c new file mode 100644 -index 0000000..1b2f4e1 +index 0000000..2a287de --- /dev/null +++ b/drivers/net/fec_mpc52xx/fec_phy.c -@@ -0,0 +1,532 @@ +@@ -0,0 +1,526 @@ +/* + * arch/ppc/52xx_io/fec_phy.c + * @@ -1240,14 +1195,8 @@ index 0000000..1b2f4e1 +#include +#include +#include -+ -+#ifdef CONFIG_PPC_EFIKA -+#include -+#else +#include +#include -+#endif -+ +#include "fec_phy.h" +#include "fec.h" + @@ -1457,7 +1406,7 @@ index 0000000..1b2f4e1 + }, + (const phy_cmd_t []) { /* startup */ + /* restart auto-negotiation */ -+ { mk_mii_write(MII_BMCR, (BMCR_ANENABLE | BMCR_ANRESTART) ), ++ { mk_mii_write(MII_BMCR, (BMCR_ANENABLE | BMCR_ANRESTART)), + NULL }, + { mk_mii_end, } + }, @@ -1830,5 +1779,5 @@ index 0000000..5c23bff + +extern int fec_ioctl(struct net_device *, struct ifreq *rq, int cmd); -- -1.4.3.2 +1.4.4.2 diff --git a/debian/patches/features/powerpc/efika/0021-POWERPC-Copy-bestcomm-support-files-into-arch-powerpc.txt b/debian/patches/features/powerpc/efika/0021-POWERPC-Copy-bestcomm-support-files-into-arch-powerpc.txt new file mode 100644 index 000000000..958ca7f20 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0021-POWERPC-Copy-bestcomm-support-files-into-arch-powerpc.txt @@ -0,0 +1,1335 @@ +From 50ea8834d3b4c79ddaa8f1df88d285ebe8e71cd4 Mon Sep 17 00:00:00 2001 +From: Grant Likely +Date: Mon, 4 Dec 2006 22:19:21 -0700 +Subject: [PATCH] [POWERPC] Copy bestcomm support files into arch/powerpc + +Signed-off-by: Grant Likely +--- + arch/powerpc/platforms/52xx/bestcomm.c | 408 ++++++++++++++++++++ + arch/powerpc/platforms/52xx/bestcomm.h | 473 ++++++++++++++++++++++++ + arch/powerpc/platforms/52xx/fec.c | 174 +++++++++ + arch/powerpc/platforms/52xx/fec.h | 71 ++++ + arch/powerpc/platforms/52xx/sdma_fec_rx_task.c | 71 ++++ + arch/powerpc/platforms/52xx/sdma_fec_tx_task.c | 84 +++++ + 6 files changed, 1281 insertions(+), 0 deletions(-) + +diff --git a/arch/powerpc/platforms/52xx/bestcomm.c b/arch/powerpc/platforms/52xx/bestcomm.c +new file mode 100644 +index 0000000..ef45e02 +--- /dev/null ++++ b/arch/powerpc/platforms/52xx/bestcomm.c +@@ -0,0 +1,408 @@ ++/* ++ * arch/ppc/syslib/bestcomm/bestcomm.c ++ * ++ * Driver for MPC52xx processor BestComm peripheral controller ++ * ++ * Author: Dale Farnsworth ++ * ++ * 2003-2004 (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. ++ * ++ * HISTORY: ++ * ++ * 2005-08-14 Converted to platform driver by ++ * Andrey Volkov , Varma Electronics Oy ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "bestcomm.h" ++ ++#define DRIVER_NAME "mpc52xx-sdma" ++ ++struct sdma_io sdma; ++ ++static spinlock_t sdma_lock = SPIN_LOCK_UNLOCKED; ++ ++#ifdef CONFIG_BESTCOMM_DEBUG ++void sdma_dump(void) ++{ ++ int i; ++ printk("** SDMA registers: pa = %08x, va = %08x\n", sdma.base_reg_addr, sdma.io); ++ printk("** taskBar = %08x\n", sdma.io->taskBar); ++ printk("** currentPointer = %08x\n", sdma.io->currentPointer); ++ printk("** endPointer = %08x\n", sdma.io->endPointer); ++ printk("** variablePointer = %08x\n", sdma.io->variablePointer); ++ ++ printk("** IntVect1 = %08x\n", sdma.io->IntVect1); ++ printk("** IntVect2 = %08x\n", sdma.io->IntVect2); ++ printk("** PtdCntrl = %08x\n", sdma.io->PtdCntrl); ++ ++ printk("** IntPend = %08x\n", sdma.io->IntPend); ++ printk("** IntMask = %08x\n", sdma.io->IntMask); ++ ++ printk("** TCR dump:"); ++ ++ for (i=0;i<16;i++) { ++ if(i%8 == 0) ++ printk("\n** %02X:",i); ++ printk(" %04X",sdma.io->tcr[i]); ++ } ++ printk("\n** IPR dump:"); ++ for (i=0;i<32;i++) { ++ if(i%16 == 0) ++ printk("\n** %02X:",i); ++ printk(" %02X",sdma.io->ipr[i]); ++ } ++ printk("\n** cReqSelect = %08x\n", sdma.io->cReqSelect); ++ printk("** task_size0 = %08x\n", sdma.io->task_size0); ++ printk("** task_size1 = %08x\n", sdma.io->task_size1); ++ printk("** MDEDebug = %08x\n", sdma.io->MDEDebug); ++ printk("** ADSDebug = %08x\n", sdma.io->ADSDebug); ++ printk("** Value1 = %08x\n", sdma.io->Value1); ++ printk("** Value2 = %08x\n", sdma.io->Value2); ++ printk("** Control = %08x\n", sdma.io->Control); ++ printk("** Status = %08x\n", sdma.io->Status); ++ printk("** PTDDebug = %08x\n", sdma.io->PTDDebug); ++} ++#endif ++ ++#ifdef CONFIG_BESTCOMM_DEBUG ++#define SDMA_DUMP_REGS() sdma_dump() ++#else ++#define SDMA_DUMP_REGS() ++#endif ++ ++/* ++ * Use a very simple SRAM allocator. ++ * There is no mechanism for freeing space. ++ * In an attempt to minimize internal fragmentation, the SRAM is ++ * divided into two areas. ++ * ++ * Area 1 is at the beginning of SRAM ++ * and is used for allocations requiring alignments of 16 bytes or less. ++ * Successive allocations return higher addresses. ++ * ++ * Area 2 is at the end of SRAM and is used for the remaining allocations. ++ * Successive allocations return lower addresses. ++ * ++ * I've considered adding routines to support the freeing of SRAM allocations, ++ * but the SRAM is so small (16K) that fragmentation can quickly cause the ++ * SRAM to be unusable. If you can come up with a slick way to free SRAM ++ * memory without the fragmentation problem, please do so. ++ */ ++ ++static u8 *area1_end; ++static u8 *area2_begin; ++ ++void *sdma_sram_alloc(int size, int alignment, u32 *dma_handle) ++{ ++ u8 *a; ++ ++ spin_lock(&sdma_lock); ++ ++ /* alignment must be a power of 2 */ ++ BUG_ON(alignment & (alignment - 1)); ++ ++ if (alignment < 16) { ++ a = (u8 *)(((u32)area1_end + (alignment-1)) & ~(alignment-1)); ++ if (a + size <= area2_begin) ++ area1_end = a + size; ++ else ++ a = 0; /* out of memory */ ++ } else { ++ a = (u8 *)(((u32)area2_begin - size) & ~(alignment - 1)); ++ if (a >= area1_end) ++ area2_begin = a; ++ else ++ a = 0; /* out of memory */ ++ } ++ if(a && dma_handle) ++ *dma_handle = sdma_sram_pa(a); ++ spin_unlock(&sdma_lock); ++ return (void *)a; ++} ++ ++/* this will need to be updated if Freescale changes their task code FDT */ ++static u32 fdt_ops[] = { ++ 0xa0045670, /* FDT[48] */ ++ 0x80045670, /* FDT[49] */ ++ 0x21800000, /* FDT[50] */ ++ 0x21e00000, /* FDT[51] */ ++ 0x21500000, /* FDT[52] */ ++ 0x21400000, /* FDT[53] */ ++ 0x21500000, /* FDT[54] */ ++ 0x20400000, /* FDT[55] */ ++ 0x20500000, /* FDT[56] */ ++ 0x20800000, /* FDT[57] */ ++ 0x20a00000, /* FDT[58] */ ++ 0xc0170000, /* FDT[59] */ ++ 0xc0145670, /* FDT[60] */ ++ 0xc0345670, /* FDT[61] */ ++ 0xa0076540, /* FDT[62] */ ++ 0xa0000760, /* FDT[63] */ ++}; ++ ++static int new_task_number(void) ++{ ++ struct sdma_tdt *tdt; ++ int i; ++ ++ spin_lock(&sdma_lock); ++ ++ tdt = sdma.tdt; ++ for (i=0; istart == 0) ++ break; ++ if (i == SDMA_MAX_TASKS) ++ i = -1; ++ ++ spin_unlock(&sdma_lock); ++ ++ return i; ++} ++ ++int sdma_load_task(u32 *task_image) ++{ ++ struct sdma_task_header *head = (struct sdma_task_header *)task_image; ++ struct sdma_tdt *tdt; ++ int tasknum; ++ u32 *desc; ++ u32 *var_src, *var_dst; ++ u32 *inc_src; ++ void *start; ++ ++ BUG_ON(head->magic != SDMA_TASK_MAGIC); ++ ++ tasknum = new_task_number(); ++ if (tasknum < 0) ++ return -ENOMEM; ++ ++ desc = (u32 *)(head + 1); ++ var_src = desc + head->desc_size; ++ inc_src = var_src + head->var_size; ++ ++ tdt = &sdma.tdt[tasknum]; ++ ++ start = sdma_sram_alloc(head->desc_size * sizeof(u32), 4, &tdt->start); ++ if (!start) ++ return -ENOMEM; ++ tdt->stop = tdt->start + (head->desc_size - 1)*sizeof(u32); ++ var_dst = sdma_sram_va(tdt->var); ++ ++ memcpy(start, desc, head->desc_size * sizeof(u32)); ++ memcpy(&var_dst[head->first_var], var_src, head->var_size * sizeof(u32)); ++ memcpy(&var_dst[SDMA_MAX_VAR], inc_src, head->inc_size * sizeof(u32)); ++ ++ return tasknum; ++} ++ ++void sdma_set_initiator(int task, int initiator) ++{ ++ int i; ++ int num_descs; ++ u32 *desc; ++ int next_drd_has_initiator; ++ ++ sdma_set_tcr_initiator(task, initiator); ++ ++ desc = sdma_task_desc(task); ++ next_drd_has_initiator = 1; ++ num_descs = sdma_task_num_descs(task); ++ ++ for (i=0; icookie = cookie; ++ } ++ ++ s->num_bd = queue_size; ++ return s; ++} ++ ++void sdma_free(struct sdma *s) ++{ ++ if (s->cookie) ++ kfree(s->cookie); ++ kfree(s); ++} ++ ++static int __devinit mpc52xx_sdma_probe(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ int task; ++ u32 *context; ++ u32 *fdt; ++ struct sdma_tdt *tdt; ++ struct resource *mem_io, *mem_sram; ++ u32 tdt_pa, var_pa, context_pa, fdt_pa; ++ int ret = -ENODEV; ++ ++ mem_io = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ mem_sram = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ if (!mem_io || !mem_sram) ++ goto out; ++ ++ if (!request_mem_region(mem_io->start, mem_io->end - mem_io->start + 1, DRIVER_NAME)) { ++ printk(KERN_ERR DRIVER_NAME " - resource unavailable\n"); ++ goto out; ++ } ++ sdma.base_reg_addr = mem_io->start; ++ ++ sdma.io = ioremap_nocache(mem_io->start, sizeof(struct mpc52xx_sdma)); ++ ++ if (!sdma.io ) { ++ printk(KERN_ERR DRIVER_NAME " - failed to map sdma regs\n"); ++ ret = -ENOMEM; ++ goto map_io_error; ++ } ++ ++ SDMA_DUMP_REGS(); ++ ++ sdma.sram_size = mem_sram->end - mem_sram->start + 1; ++ if (!request_mem_region(mem_sram->start, sdma.sram_size, DRIVER_NAME)) { ++ printk(KERN_ERR DRIVER_NAME " - resource unavailable\n"); ++ goto req_sram_error; ++ } ++ ++ sdma.base_sram_addr = mem_sram->start; ++ sdma.sram = ioremap_nocache(mem_sram->start, sdma.sram_size); ++ if (!sdma.sram ) { ++ printk(KERN_ERR DRIVER_NAME " - failed to map sdma sram\n"); ++ ret = -ENOMEM; ++ goto map_sram_error; ++ } ++ ++ area1_end = sdma.sram; ++ area2_begin = area1_end + sdma.sram_size; ++ ++ memset(area1_end, 0, sdma.sram_size); ++ ++ /* allocate space for task descriptors, contexts, and var tables */ ++ sdma.tdt = sdma_sram_alloc(sizeof(struct sdma_tdt) * SDMA_MAX_TASKS, 4, &tdt_pa); ++ ++ context = sdma_sram_alloc(SDMA_CONTEXT_SIZE * SDMA_MAX_TASKS, ++ SDMA_CONTEXT_ALIGN, &context_pa); ++ sdma.var = sdma_sram_alloc( (SDMA_VAR_SIZE + SDMA_INC_SIZE) * SDMA_MAX_TASKS, ++ SDMA_VAR_ALIGN, &var_pa); ++ fdt = sdma_sram_alloc(SDMA_FDT_SIZE, SDMA_FDT_ALIGN, &fdt_pa); ++ memcpy(&fdt[48], fdt_ops, sizeof(fdt_ops)); ++ ++ out_be32(&sdma.io->taskBar, tdt_pa); ++ ++ tdt = sdma.tdt; ++ for (task=0; task < SDMA_MAX_TASKS; task++) { ++ out_be16(&sdma.io->tcr[task], 0); ++ out_8(&sdma.io->ipr[task], 0); ++ ++ tdt->context = context_pa; ++ tdt->var = var_pa; ++ tdt->fdt = fdt_pa; ++ var_pa += (SDMA_MAX_VAR + SDMA_MAX_INC)*sizeof(u32); ++ context_pa += SDMA_MAX_CONTEXT*sizeof(u32); ++ tdt++; ++ } ++ ++ out_8(&sdma.io->ipr[SDMA_INITIATOR_ALWAYS], SDMA_IPR_ALWAYS); ++ ++ /* Disable COMM Bus Prefetch, apparently it's not reliable yet */ ++ out_be16(&sdma.io->PtdCntrl, in_be16(&sdma.io->PtdCntrl) | 1); ++ ++ printk(KERN_INFO "MPC52xx BestComm inited\n"); ++ ++ return 0; ++ ++map_sram_error: ++ release_mem_region(mem_sram->start, sdma.sram_size); ++req_sram_error: ++ iounmap(sdma.io); ++map_io_error: ++ release_mem_region(mem_io->start, mem_io->end - mem_io->start + 1); ++out: ++ printk(KERN_ERR "DMA: MPC52xx BestComm init FAILED !!!\n"); ++ return ret; ++} ++ ++ ++static struct device_driver mpc52xx_sdma_driver = { ++ .owner = THIS_MODULE, ++ .name = DRIVER_NAME, ++ .bus = &platform_bus_type, ++ .probe = mpc52xx_sdma_probe, ++/* .remove = mpc52xx_sdma_remove, TODO */ ++#ifdef CONFIG_PM ++/* .suspend = mpc52xx_sdma_suspend, TODO */ ++/* .resume = mpc52xx_sdma_resume, TODO */ ++#endif ++}; ++ ++static int __init ++mpc52xx_sdma_init(void) ++{ ++ printk(KERN_INFO "DMA: MPC52xx BestComm driver\n"); ++ return driver_register(&mpc52xx_sdma_driver); ++} ++ ++#ifdef MODULE ++static void __exit ++mpc52xx_sdma_exit(void) ++{ ++ driver_unregister(&mpc52xx_sdma_driver); ++} ++#endif ++ ++#ifndef MODULE ++ subsys_initcall(mpc52xx_sdma_init); ++#else ++ module_init(mpc52xx_sdma_init); ++ module_exit(mpc52xx_sdma_exit); ++#endif ++ ++ ++MODULE_DESCRIPTION("Freescale MPC52xx BestComm DMA"); ++MODULE_LICENSE("GPL"); ++ ++EXPORT_SYMBOL(sdma_sram_alloc); ++EXPORT_SYMBOL(sdma_load_task); ++EXPORT_SYMBOL(sdma_set_initiator); ++EXPORT_SYMBOL(sdma_free); ++EXPORT_SYMBOL(sdma); ++ ++ +diff --git a/arch/powerpc/platforms/52xx/bestcomm.h b/arch/powerpc/platforms/52xx/bestcomm.h +new file mode 100644 +index 0000000..14bf397 +--- /dev/null ++++ b/arch/powerpc/platforms/52xx/bestcomm.h +@@ -0,0 +1,473 @@ ++/* ++ * arch/ppc/syslib/bestcomm/bestcomm.h ++ * ++ * Driver for MPC52xx processor BestComm peripheral controller ++ * ++ * Author: Dale Farnsworth ++ * ++ * 2003-2004 (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. ++ * ++ * HISTORY: ++ * ++ * 2005-08-14 Converted to platform driver by ++ * Andrey Volkov , Varma Electronics Oy ++ */ ++ ++#ifndef __BESTCOMM_BESTCOMM_H__ ++#define __BESTCOMM_BESTCOMM_H__ ++ ++/* Buffer Descriptor definitions */ ++struct sdma_bd { ++ u32 status; ++ void *data; ++}; ++ ++struct sdma_bd2 { ++ u32 status; ++ void *data1; ++ void *data2; ++}; ++ ++struct sdma_io { ++ unsigned long base_reg_addr; ++ struct mpc52xx_sdma __iomem *io; ++ unsigned long base_sram_addr; ++ void __iomem *sram; ++ size_t sram_size; ++ ++ struct sdma_tdt __iomem *tdt; ++ u32 __iomem *var; ++}; ++extern struct sdma_io sdma; ++ ++#define sdma_sram_pa(virt) (((unsigned long)(((void __iomem *)(virt))-sdma.sram))+sdma.base_sram_addr) ++#define sdma_sram_va(pa) ((void __iomem *)((((unsigned long)(pa))-sdma.base_sram_addr)+((unsigned long)sdma.sram))) ++ ++#define sdma_io_pa(virt) (((unsigned long)(((void __iomem *)(virt))-((void __iomem *)sdma.io)))+sdma.base_reg_addr) ++#define sdma_io_va(pa) ((void __iomem *)((((unsigned long)(pa))-sdma.base_reg_addr)+((unsigned long)sdma.io))) ++ ++#define SDMA_LEN_BITS 26 ++#define SDMA_LEN_MASK ((1 << SDMA_LEN_BITS) - 1) ++ ++#define SDMA_BD_READY 0x40000000UL ++ ++#define SDMA_FEC_TX_BD_TFD 0x08000000UL /* transmit frame done */ ++#define SDMA_FEC_TX_BD_INT 0x04000000UL /* Interrupt */ ++#define SDMA_FEC_TX_BD_TFD_INIT (SDMA_BD_READY | SDMA_FEC_TX_BD_TFD | \ ++ SDMA_FEC_TX_BD_INT) ++ ++struct sdma { ++ union { ++ struct sdma_bd *bd; ++ struct sdma_bd2 *bd2; ++ }; ++ void **cookie; ++ u16 index; ++ u16 outdex; ++ u16 num_bd; ++ s16 tasknum; ++ u32 flags; ++}; ++ ++#define SDMA_FLAGS_NONE 0x0000 ++#define SDMA_FLAGS_ENABLE_TASK 0x0001 ++#define SDMA_FLAGS_BD2 0x0002 ++ ++/* Task Descriptor Table Entry */ ++struct sdma_tdt { ++ u32 start; ++ u32 stop; ++ u32 var; ++ u32 fdt; ++ u32 exec_status; /* used internally by SmartComm engine */ ++ u32 mvtp; /* used internally by SmartComm engine */ ++ u32 context; ++ u32 litbase; ++}; ++ ++//extern struct sdma_tdt *sdma_tdt; ++ ++#define SDMA_MAX_TASKS 16 ++#define SDMA_MAX_VAR 24 ++#define SDMA_MAX_INC 8 ++#define SDMA_MAX_FDT 64 ++#define SDMA_MAX_CONTEXT 20 ++#define SDMA_CONTEXT_SIZE SDMA_MAX_CONTEXT * sizeof(u32) ++#define SDMA_CONTEXT_ALIGN 0x100 ++#define SDMA_VAR_SIZE SDMA_MAX_VAR * sizeof(u32) ++#define SDMA_VAR_ALIGN 0x80 ++#define SDMA_INC_SIZE SDMA_MAX_INC * sizeof(u32) ++#define SDMA_FDT_SIZE SDMA_MAX_FDT * sizeof(u32) ++#define SDMA_FDT_ALIGN 0x100 ++#define SDMA_BD_ALIGN 0x10 ++ ++#define TASK_ENABLE 0x8000 ++ ++#ifndef DPRINK ++ #ifdef CONFIG_BESTCOMM_DEBUG ++ #define DPRINTK(a,b...) printk(KERN_DEBUG "sdma: %s: " a, __FUNCTION__ , ## b) ++ #else ++ #define DPRINTK(a,b...) ++ #endif ++#endif ++ ++static inline void sdma_enable_task(int task) ++{ ++ DPRINTK("***DMA enable task (%d): tdt = %08x\n",task, sdma.tdt); ++ DPRINTK("***tdt->start = %08x\n",sdma.tdt[task].start); ++ DPRINTK("***tdt->stop = %08x\n",sdma.tdt[task].stop); ++ DPRINTK("***tdt->var = %08x\n",sdma.tdt[task].var); ++ DPRINTK("***tdt->fdt = %08x\n",sdma.tdt[task].fdt); ++ DPRINTK("***tdt->status = %08x\n",sdma.tdt[task].exec_status); ++ DPRINTK("***tdt->mvtp = %08x\n",sdma.tdt[task].mvtp); ++ DPRINTK("***tdt->context = %08x\n",sdma.tdt[task].context); ++ DPRINTK("***tdt->litbase = %08x\n",sdma.tdt[task].litbase); ++ DPRINTK("***--------------\n"); ++ ++ u16 reg = in_be16(&sdma.io->tcr[task]); ++ DPRINTK("***enable task: &sdma.io->tcr=%08x, reg = %04x\n", &sdma.io->tcr, reg); ++ out_be16(&sdma.io->tcr[task], reg | TASK_ENABLE); ++} ++ ++static inline void sdma_disable_task(int task) ++{ ++ u16 reg = in_be16(&sdma.io->tcr[task]); ++ DPRINTK("***disable task(%d): reg = %04x\n", task, reg); ++ out_be16(&sdma.io->tcr[task], reg & ~TASK_ENABLE); ++} ++ ++static inline int sdma_irq(struct sdma *s) ++{ ++ return MPC52xx_SDMA_IRQ_BASE + s->tasknum; ++} ++ ++static inline void sdma_enable(struct sdma *s) ++{ ++ sdma_enable_task(s->tasknum); ++} ++ ++static inline void sdma_disable(struct sdma *s) ++{ ++ sdma_disable_task(s->tasknum); ++} ++ ++static inline int sdma_queue_empty(struct sdma *s) ++{ ++ return s->index == s->outdex; ++} ++ ++static inline void sdma_clear_irq(struct sdma *s) ++{ ++ out_be32(&sdma.io->IntPend, 1 << s->tasknum); ++} ++ ++static inline int sdma_next_index(struct sdma *s) ++{ ++ return ((s->index + 1) == s->num_bd) ? 0 : s->index + 1; ++} ++ ++static inline int sdma_next_outdex(struct sdma *s) ++{ ++ return ((s->outdex + 1) == s->num_bd) ? 0 : s->outdex + 1; ++} ++ ++static inline int sdma_queue_full(struct sdma *s) ++{ ++ return s->outdex == sdma_next_index(s); ++} ++ ++static inline int sdma_buffer_done(struct sdma *s) ++{ ++#ifdef CONFIG_BESTCOMM_DEBUG ++ BUG_ON(s->flags & SDMA_FLAGS_BD2); ++#endif ++ if (sdma_queue_empty(s)) ++ return 0; ++ return (s->bd[s->outdex].status & SDMA_BD_READY) == 0; ++} ++ ++static inline int sdma_buffer2_done(struct sdma *s) ++{ ++#ifdef CONFIG_BESTCOMM_DEBUG ++ BUG_ON(!(s->flags & SDMA_FLAGS_BD2)); ++#endif ++ if (sdma_queue_empty(s)) ++ return 0; ++ ++ return (s->bd2[s->outdex].status & SDMA_BD_READY) == 0; ++} ++ ++static inline u32 *sdma_task_desc(int task) ++{ ++ return sdma_sram_va(sdma.tdt[task].start); ++} ++ ++static inline u32 sdma_task_num_descs(int task) ++{ ++ return (sdma.tdt[task].stop - sdma.tdt[task].start)/sizeof(u32) + 1; ++} ++ ++static inline u32 *sdma_task_var(int task) ++{ ++ return sdma_sram_va(sdma.tdt[task].var); ++} ++ ++static inline u32 *sdma_task_inc(int task) ++{ ++ return &sdma_task_var(task)[SDMA_MAX_VAR]; ++} ++ ++static inline void sdma_set_tcr_initiator(int task, int initiator) { ++ u16 *tcr = &sdma.io->tcr[task]; ++ out_be16(tcr, (in_be16(tcr) & ~0x1f00) | (initiator << 8)); ++} ++ ++#define SDMA_DRD_INITIATOR_SHIFT 21 ++ ++static inline int sdma_desc_initiator(u32 desc) ++{ ++ return (desc >> SDMA_DRD_INITIATOR_SHIFT) & 0x1f; ++} ++ ++static inline void sdma_set_desc_initiator(u32 *desc, int initiator) ++{ ++ *desc = (*desc & ~(0x1f << SDMA_DRD_INITIATOR_SHIFT)) | ++ ((initiator << SDMA_DRD_INITIATOR_SHIFT) & 0x1f); ++} ++ ++static inline void sdma_submit_buffer(struct sdma *s, void *cookie, void *data, ++ int length) ++{ ++#ifdef CONFIG_BESTCOMM_DEBUG ++ BUG_ON(s->flags & SDMA_FLAGS_BD2); ++#endif ++ s->cookie[s->index] = cookie; ++ s->bd[s->index].data = data; ++ s->bd[s->index].status = SDMA_BD_READY | length; ++ s->index = sdma_next_index(s); ++ if (s->flags & SDMA_FLAGS_ENABLE_TASK) ++ sdma_enable_task(s->tasknum); ++} ++ ++/* ++ * Special submit_buffer function to submit last buffer of a frame to ++ * the FEC tx task. tfd means "transmit frame done". ++ */ ++static inline void sdma_fec_tfd_submit_buffer(struct sdma *s, void *cookie, ++ void *data, int length) ++{ ++#ifdef CONFIG_BESTCOMM_DEBUG ++ BUG_ON(s->flags & SDMA_FLAGS_BD2); ++#endif ++ s->cookie[s->index] = cookie; ++ s->bd[s->index].data = data; ++ s->bd[s->index].status = SDMA_FEC_TX_BD_TFD_INIT | length; ++ s->index = sdma_next_index(s); ++ sdma_enable_task(s->tasknum); ++} ++ ++static inline void *sdma_retrieve_buffer(struct sdma *s, int *length) ++{ ++ void *cookie = s->cookie[s->outdex]; ++ ++#ifdef CONFIG_BESTCOMM_DEBUG ++ BUG_ON(s->flags & SDMA_FLAGS_BD2); ++#endif ++ if (length) ++ *length = s->bd[s->outdex].status & SDMA_LEN_MASK; ++ s->outdex = sdma_next_outdex(s); ++ return cookie; ++} ++ ++static inline void sdma_submit_buffer2(struct sdma *s, void *cookie, ++ void *data1, void *data2, int length) ++{ ++#ifdef CONFIG_BESTCOMM_DEBUG ++ BUG_ON(!(s->flags & SDMA_FLAGS_BD2)); ++#endif ++ s->cookie[s->index] = cookie; ++ s->bd2[s->index].data1 = data1; ++ s->bd2[s->index].data2 = data2; ++ s->bd2[s->index].status = SDMA_BD_READY | length; ++ s->index = sdma_next_index(s); ++ if (s->flags & SDMA_FLAGS_ENABLE_TASK) ++ sdma_enable_task(s->tasknum); ++} ++ ++static inline void *sdma_retrieve_buffer2(struct sdma *s, int *length) ++{ ++ void *cookie = s->cookie[s->outdex]; ++ ++#ifdef CONFIG_BESTCOMM_DEBUG ++ BUG_ON(!(s->flags & SDMA_FLAGS_BD2)); ++#endif ++ if (length) ++ *length = s->bd2[s->outdex].status & SDMA_LEN_MASK; ++ s->outdex = sdma_next_outdex(s); ++ return cookie; ++} ++ ++#define SDMA_TASK_MAGIC 0x4243544B /* 'BCTK' */ ++ ++/* the size fields are given in number of 32-bit words */ ++struct sdma_task_header { ++ u32 magic; ++ u8 desc_size; ++ u8 var_size; ++ u8 inc_size; ++ u8 first_var; ++ u8 reserved[8]; ++}; ++ ++#define SDMA_DESC_NOP 0x000001f8 ++#define SDMA_LCD_MASK 0x80000000 ++#define SDMA_DRD_EXTENDED 0x40000000 ++ ++#define sdma_drd_is_extended(desc) ((desc) & SDMA_DRD_EXTENDED) ++ ++static inline int sdma_desc_is_drd(u32 desc) { ++ return !(desc & SDMA_LCD_MASK) && desc != SDMA_DESC_NOP; ++}; ++ ++#define SDMA_PRAGMA_BIT_RSV 7 /* reserved pragma bit */ ++#define SDMA_PRAGMA_BIT_PRECISE_INC 6 /* increment 0=when possible, */ ++ /* 1=iter end */ ++#define SDMA_PRAGMA_BIT_RST_ERROR_NO 5 /* don't reset errors on */ ++ /* task enable */ ++#define SDMA_PRAGMA_BIT_PACK 4 /* pack data enable */ ++#define SDMA_PRAGMA_BIT_INTEGER 3 /* data alignment */ ++ /* 0=frac(msb), 1=int(lsb) */ ++#define SDMA_PRAGMA_BIT_SPECREAD 2 /* XLB speculative read */ ++#define SDMA_PRAGMA_BIT_CW 1 /* write line buffer enable */ ++#define SDMA_PRAGMA_BIT_RL 0 /* read line buffer enable */ ++ ++#define SDMA_STD_PRAGMA ((0 << SDMA_PRAGMA_BIT_RSV) | \ ++ (0 << SDMA_PRAGMA_BIT_PRECISE_INC) | \ ++ (0 << SDMA_PRAGMA_BIT_RST_ERROR_NO) | \ ++ (0 << SDMA_PRAGMA_BIT_PACK) | \ ++ (0 << SDMA_PRAGMA_BIT_INTEGER) | \ ++ (1 << SDMA_PRAGMA_BIT_SPECREAD) | \ ++ (1 << SDMA_PRAGMA_BIT_CW) | \ ++ (1 << SDMA_PRAGMA_BIT_RL)) ++ ++#define SDMA_PCI_PRAGMA ((0 << SDMA_PRAGMA_BIT_RSV) | \ ++ (0 << SDMA_PRAGMA_BIT_PRECISE_INC) | \ ++ (0 << SDMA_PRAGMA_BIT_RST_ERROR_NO) | \ ++ (0 << SDMA_PRAGMA_BIT_PACK) | \ ++ (1 << SDMA_PRAGMA_BIT_INTEGER) | \ ++ (1 << SDMA_PRAGMA_BIT_SPECREAD) | \ ++ (1 << SDMA_PRAGMA_BIT_CW) | \ ++ (1 << SDMA_PRAGMA_BIT_RL)) ++ ++#define SDMA_ATA_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_CRC16_DP_0_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_CRC16_DP_1_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_FEC_RX_BD_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_FEC_TX_BD_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_DP_0_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_DP_1_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_DP_2_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_DP_3_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_DP_BD_0_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_DP_BD_1_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_RX_BD_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_TX_BD_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_GEN_LPC_PRAGMA SDMA_STD_PRAGMA ++#define SDMA_PCI_RX_PRAGMA SDMA_PCI_PRAGMA ++#define SDMA_PCI_TX_PRAGMA SDMA_PCI_PRAGMA ++ ++static inline void sdma_set_task_pragma(int task, int pragma) ++{ ++ u32 *fdt = &sdma.tdt[task].fdt; ++ *fdt = (*fdt & ~0xff) | pragma; ++} ++ ++static inline void sdma_set_task_auto_start(int task, int next_task) ++{ ++ u16 *tcr = &sdma.io->tcr[task]; ++ out_be16(tcr, (in_be16(tcr) & ~0xff) | 0x00c0 | next_task); ++} ++ ++#define SDMA_INITIATOR_ALWAYS 0 ++#define SDMA_INITIATOR_SCTMR_0 1 ++#define SDMA_INITIATOR_SCTMR_1 2 ++#define SDMA_INITIATOR_FEC_RX 3 ++#define SDMA_INITIATOR_FEC_TX 4 ++#define SDMA_INITIATOR_ATA_RX 5 ++#define SDMA_INITIATOR_ATA_TX 6 ++#define SDMA_INITIATOR_SCPCI_RX 7 ++#define SDMA_INITIATOR_SCPCI_TX 8 ++#define SDMA_INITIATOR_PSC3_RX 9 ++#define SDMA_INITIATOR_PSC3_TX 10 ++#define SDMA_INITIATOR_PSC2_RX 11 ++#define SDMA_INITIATOR_PSC2_TX 12 ++#define SDMA_INITIATOR_PSC1_RX 13 ++#define SDMA_INITIATOR_PSC1_TX 14 ++#define SDMA_INITIATOR_SCTMR_2 15 ++#define SDMA_INITIATOR_SCLPC 16 ++#define SDMA_INITIATOR_PSC5_RX 17 ++#define SDMA_INITIATOR_PSC5_TX 18 ++#define SDMA_INITIATOR_PSC4_RX 19 ++#define SDMA_INITIATOR_PSC4_TX 20 ++#define SDMA_INITIATOR_I2C2_RX 21 ++#define SDMA_INITIATOR_I2C2_TX 22 ++#define SDMA_INITIATOR_I2C1_RX 23 ++#define SDMA_INITIATOR_I2C1_TX 24 ++#define SDMA_INITIATOR_PSC6_RX 25 ++#define SDMA_INITIATOR_PSC6_TX 26 ++#define SDMA_INITIATOR_IRDA_RX 25 ++#define SDMA_INITIATOR_IRDA_TX 26 ++#define SDMA_INITIATOR_SCTMR_3 27 ++#define SDMA_INITIATOR_SCTMR_4 28 ++#define SDMA_INITIATOR_SCTMR_5 29 ++#define SDMA_INITIATOR_SCTMR_6 30 ++#define SDMA_INITIATOR_SCTMR_7 31 ++ ++#define SDMA_IPR_ALWAYS 7 ++#define SDMA_IPR_SCTMR_0 2 ++#define SDMA_IPR_SCTMR_1 2 ++#define SDMA_IPR_FEC_RX 6 ++#define SDMA_IPR_FEC_TX 5 ++#define SDMA_IPR_ATA_RX 4 ++#define SDMA_IPR_ATA_TX 3 ++#define SDMA_IPR_SCPCI_RX 2 ++#define SDMA_IPR_SCPCI_TX 2 ++#define SDMA_IPR_PSC3_RX 2 ++#define SDMA_IPR_PSC3_TX 2 ++#define SDMA_IPR_PSC2_RX 2 ++#define SDMA_IPR_PSC2_TX 2 ++#define SDMA_IPR_PSC1_RX 2 ++#define SDMA_IPR_PSC1_TX 2 ++#define SDMA_IPR_SCTMR_2 2 ++#define SDMA_IPR_SCLPC 2 ++#define SDMA_IPR_PSC5_RX 2 ++#define SDMA_IPR_PSC5_TX 2 ++#define SDMA_IPR_PSC4_RX 2 ++#define SDMA_IPR_PSC4_TX 2 ++#define SDMA_IPR_I2C2_RX 2 ++#define SDMA_IPR_I2C2_TX 2 ++#define SDMA_IPR_I2C1_RX 2 ++#define SDMA_IPR_I2C1_TX 2 ++#define SDMA_IPR_PSC6_RX 2 ++#define SDMA_IPR_PSC6_TX 2 ++#define SDMA_IPR_IRDA_RX 2 ++#define SDMA_IPR_IRDA_TX 2 ++#define SDMA_IPR_SCTMR_3 2 ++#define SDMA_IPR_SCTMR_4 2 ++#define SDMA_IPR_SCTMR_5 2 ++#define SDMA_IPR_SCTMR_6 2 ++#define SDMA_IPR_SCTMR_7 2 ++ ++extern struct sdma *sdma_alloc(int request_queue_size); ++extern void sdma_free(struct sdma *sdma_struct); ++extern int sdma_load_task(u32 *task_image); ++extern void *sdma_sram_alloc(int size, int alignment, u32 *dma_handle); ++extern void sdma_init_bd(struct sdma *s); ++extern void sdma_init_bd2(struct sdma *s); ++ ++#define FIELD_OFFSET(s,f) ((unsigned long)(&(((struct s*)0)->f))) ++ ++#endif /* __BESTCOMM_BESTCOMM_H__ */ +diff --git a/arch/powerpc/platforms/52xx/fec.c b/arch/powerpc/platforms/52xx/fec.c +new file mode 100644 +index 0000000..8756856 +--- /dev/null ++++ b/arch/powerpc/platforms/52xx/fec.c +@@ -0,0 +1,174 @@ ++/* ++ * arch/ppc/syslib/bestcomm/fec.c ++ * ++ * Driver for MPC52xx processor BestComm FEC controller ++ * ++ * Author: Dale Farnsworth ++ * ++ * 2003-2004 (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. ++ * ++ * HISTORY: ++ * ++ * 2005-08-14 Converted to platform driver by ++ * Andrey Volkov , Varma Electronics Oy ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "bestcomm.h" ++#include "fec.h" ++ ++/* ++ * Initialize FEC receive task. ++ * Returns task number of FEC receive task. ++ * Returns -1 on failure ++ */ ++int sdma_fec_rx_init(struct sdma *s, phys_addr_t fifo, int maxbufsize) ++{ ++ struct sdma_fec_rx_var *var; ++ struct sdma_fec_rx_inc *inc; ++ ++ static int tasknum = -1; ++ static struct sdma_bd *bd = 0; ++ static u32 bd_pa; ++ ++ if (tasknum < 0) { ++ tasknum = sdma_load_task(sdma_fec_rx_task); ++ if (tasknum < 0) ++ return tasknum; ++ } ++ ++ if (!bd) ++ bd = (struct sdma_bd *)sdma_sram_alloc(sizeof(*bd) * s->num_bd, ++ SDMA_BD_ALIGN, &bd_pa); ++ if (!bd) ++ return -ENOMEM; ++ ++ sdma_disable_task(tasknum); ++ ++ s->tasknum = tasknum; ++ s->bd = bd; ++ s->flags = SDMA_FLAGS_NONE; ++ s->index = 0; ++ s->outdex = 0; ++ memset(bd, 0, sizeof(*bd) * s->num_bd); ++ ++ var = (struct sdma_fec_rx_var *)sdma_task_var(tasknum); ++ var->enable = sdma_io_pa(&sdma.io->tcr[tasknum]); ++ var->fifo = fifo; ++ var->bd_base = bd_pa; ++ var->bd_last = bd_pa + (s->num_bd - 1)*sizeof(struct sdma_bd); ++ var->bd_start = bd_pa; ++ var->buffer_size = maxbufsize; ++ ++ /* These are constants, they should have been in the image file */ ++ inc = (struct sdma_fec_rx_inc *)sdma_task_inc(tasknum); ++ inc->incr_bytes = -(s16)sizeof(u32); ++ inc->incr_dst = sizeof(u32); ++ inc->incr_dst_ma = sizeof(u8); ++ ++ sdma_set_task_pragma(tasknum, SDMA_FEC_RX_BD_PRAGMA); ++ sdma_set_task_auto_start(tasknum, tasknum); ++ ++ /* clear pending interrupt bits */ ++ out_be32(&sdma.io->IntPend, 1<ipr[SDMA_INITIATOR_FEC_RX], SDMA_IPR_FEC_RX); ++ ++ return tasknum; ++} ++ ++/* ++ * Return 2nd to last DRD ++ * This is an ugly hack, but at least it's only done once at initialization ++ */ ++static u32 *self_modified_drd(int tasknum) ++{ ++ u32 *desc; ++ int num_descs; ++ int drd_count; ++ int i; ++ ++ num_descs = sdma_task_num_descs(tasknum); ++ desc = sdma_task_desc(tasknum) + num_descs - 1; ++ drd_count = 0; ++ for (i=0; inum_bd, ++ SDMA_BD_ALIGN, &bd_pa); ++ if (!bd) ++ return -ENOMEM; ++ ++ sdma_disable_task(tasknum); ++ ++ s->tasknum = tasknum; ++ s->bd = bd; ++ s->flags = SDMA_FLAGS_ENABLE_TASK; ++ s->index = 0; ++ s->outdex = 0; ++ memset(bd, 0, sizeof(*bd) * s->num_bd); ++ ++ var = (struct sdma_fec_tx_var *)sdma_task_var(tasknum); ++ var->DRD = sdma_sram_pa(self_modified_drd(tasknum)); ++ var->fifo = fifo; ++ var->enable = sdma_io_pa(&sdma.io->tcr[tasknum]); ++ var->bd_base = bd_pa; ++ var->bd_last = bd_pa + (s->num_bd - 1)*sizeof(struct sdma_bd); ++ var->bd_start = bd_pa; ++ ++ /* These are constants, they should have been in the image file */ ++ inc = (struct sdma_fec_tx_inc *)sdma_task_inc(tasknum); ++ inc->incr_bytes = -(s16)sizeof(u32); ++ inc->incr_src = sizeof(u32); ++ inc->incr_src_ma = sizeof(u8); ++ ++ sdma_set_task_pragma(tasknum, SDMA_FEC_TX_BD_PRAGMA); ++ sdma_set_task_auto_start(tasknum, tasknum); ++ ++ /* clear pending interrupt bits */ ++ out_be32(&sdma.io->IntPend, 1<ipr[SDMA_INITIATOR_FEC_TX], SDMA_IPR_FEC_TX); ++ ++ return tasknum; ++} ++ ++EXPORT_SYMBOL(sdma_fec_rx_init); ++EXPORT_SYMBOL(sdma_fec_tx_init); +diff --git a/arch/powerpc/platforms/52xx/fec.h b/arch/powerpc/platforms/52xx/fec.h +new file mode 100644 +index 0000000..e3abc0f +--- /dev/null ++++ b/arch/powerpc/platforms/52xx/fec.h +@@ -0,0 +1,71 @@ ++/* ++ * arch/ppc/syslib/bestcomm/fec.h ++ * ++ * Driver for MPC52xx processor BestComm FEC controller ++ * ++ * Author: Dale Farnsworth ++ * ++ * 2003-2004 (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. ++ * ++ * HISTORY: ++ * ++ * 2005-08-14 Converted to platform driver by ++ * Andrey Volkov , Varma Electronics Oy ++ */ ++ ++#ifndef __BESTCOMM_FEC_H__ ++#define __BESTCOMM_FEC_H__ ++ ++ ++/* rx task vars that need to be set before enabling the task */ ++struct sdma_fec_rx_var { ++ u32 enable; /* (u16*) address of task's control register */ ++ u32 fifo; /* (u32*) address of fec's fifo */ ++ u32 bd_base; /* (struct sdma_bd*) beginning of ring buffer */ ++ u32 bd_last; /* (struct sdma_bd*) end of ring buffer */ ++ u32 bd_start; /* (struct sdma_bd*) current bd */ ++ u32 buffer_size; /* size of receive buffer */ ++}; ++ ++/* rx task incs that need to be set before enabling the task */ ++struct sdma_fec_rx_inc { ++ u16 pad0; ++ s16 incr_bytes; ++ u16 pad1; ++ s16 incr_dst; ++ u16 pad2; ++ s16 incr_dst_ma; ++}; ++ ++/* tx task vars that need to be set before enabling the task */ ++struct sdma_fec_tx_var { ++ u32 DRD; /* (u32*) address of self-modified DRD */ ++ u32 fifo; /* (u32*) address of fec's fifo */ ++ u32 enable; /* (u16*) address of task's control register */ ++ u32 bd_base; /* (struct sdma_bd*) beginning of ring buffer */ ++ u32 bd_last; /* (struct sdma_bd*) end of ring buffer */ ++ u32 bd_start; /* (struct sdma_bd*) current bd */ ++ u32 buffer_size; /* set by uCode for each packet */ ++}; ++ ++/* tx task incs that need to be set before enabling the task */ ++struct sdma_fec_tx_inc { ++ u16 pad0; ++ s16 incr_bytes; ++ u16 pad1; ++ s16 incr_src; ++ u16 pad2; ++ s16 incr_src_ma; ++}; ++ ++extern int sdma_fec_rx_init(struct sdma *s, phys_addr_t fifo, int maxbufsize); ++extern int sdma_fec_tx_init(struct sdma *s, phys_addr_t fifo); ++ ++extern u32 sdma_fec_rx_task[]; ++extern u32 sdma_fec_tx_task[]; ++ ++ ++#endif /* __BESTCOMM_FEC_H__ */ +diff --git a/arch/powerpc/platforms/52xx/sdma_fec_rx_task.c b/arch/powerpc/platforms/52xx/sdma_fec_rx_task.c +new file mode 100644 +index 0000000..511b036 +--- /dev/null ++++ b/arch/powerpc/platforms/52xx/sdma_fec_rx_task.c +@@ -0,0 +1,71 @@ ++/* ++ * sdma_fec_rx_task.c ++ * ++ * Automatically created based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex ++ * on Tue Mar 22 11:19:38 2005 GMT ++ */ ++ ++#include ++ ++/* ++ * The header consists of the following fields: ++ * uint32_t magic; ++ * uint8_t desc_size; ++ * uint8_t var_size; ++ * uint8_t inc_size; ++ * uint8_t first_var; ++ * uint8_t reserved[8]; ++ * ++ * The size fields contain the number of 32-bit words. ++*/ ++ ++uint32_t sdma_fec_rx_task[] = { ++ /* header */ ++ 0x4243544b, ++ 0x18060709, ++ 0x00000000, ++ 0x00000000, ++ ++ /* Task descriptors */ ++ 0x808220e3, /* LCD: idx0 = var1, idx1 = var4; idx1 <= var3; idx0 += inc4, idx1 += inc3 */ ++ 0x10601010, /* DRD1A: var4 = var2; FN=0 MORE init=3 WS=0 RS=0 */ ++ 0xb8800264, /* LCD: idx2 = *idx1, idx3 = var0; idx2 < var9; idx2 += inc4, idx3 += inc4 */ ++ 0x10001308, /* DRD1A: var4 = idx1; FN=0 MORE init=0 WS=0 RS=0 */ ++ 0x60140002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */ ++ 0x0cccfcca, /* DRD2B1: *idx3 = EU3(); EU3(*idx3,var10) */ ++ 0x80004000, /* LCDEXT: idx2 = 0x00000000; ; */ ++ 0xb8c58029, /* LCD: idx3 = *(idx1 + var00000015); idx3 once var0; idx3 += inc5 */ ++ 0x60000002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=0 RS=0 */ ++ 0x088cf8cc, /* DRD2B1: idx2 = EU3(); EU3(idx3,var12) */ ++ 0x991982f2, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var11; idx2 += inc6, idx3 += inc2 */ ++ 0x006acf80, /* DRD1A: *idx3 = *idx0; FN=0 init=3 WS=1 RS=1 */ ++ 0x80004000, /* LCDEXT: idx2 = 0x00000000; ; */ ++ 0x9999802d, /* LCD: idx3 = idx3; idx3 once var0; idx3 += inc5 */ ++ 0x70000002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */ ++ 0x034cfc4e, /* DRD2B1: var13 = EU3(); EU3(*idx1,var14) */ ++ 0x00008868, /* DRD1A: idx2 = var13; FN=0 init=0 WS=0 RS=0 */ ++ 0x99198341, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var13; idx2 += inc0, idx3 += inc1 */ ++ 0x007ecf80, /* DRD1A: *idx3 = *idx0; FN=0 init=3 WS=3 RS=3 */ ++ 0x99198272, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var9; idx2 += inc6, idx3 += inc2 */ ++ 0x046acf80, /* DRD1A: *idx3 = *idx0; FN=0 INT init=3 WS=1 RS=1 */ ++ 0x9819002d, /* LCD: idx2 = idx0; idx2 once var0; idx2 += inc5 */ ++ 0x0060c790, /* DRD1A: *idx1 = *idx2; FN=0 init=3 WS=0 RS=0 */ ++ 0x000001f8, /* NOP */ ++ ++ /* VAR[9]-VAR[14] */ ++ 0x40000000, ++ 0x7fff7fff, ++ 0x00000000, ++ 0x00000003, ++ 0x40000008, ++ 0x43ffffff, ++ ++ /* INC[0]-INC[6] */ ++ 0x40000000, ++ 0xe0000000, ++ 0xe0000000, ++ 0xa0000008, ++ 0x20000000, ++ 0x00000000, ++ 0x4000ffff, ++}; +diff --git a/arch/powerpc/platforms/52xx/sdma_fec_tx_task.c b/arch/powerpc/platforms/52xx/sdma_fec_tx_task.c +new file mode 100644 +index 0000000..d8d7fd3 +--- /dev/null ++++ b/arch/powerpc/platforms/52xx/sdma_fec_tx_task.c +@@ -0,0 +1,84 @@ ++/* ++ * sdma_fec_tx_task.c ++ * ++ * Automatically created based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex ++ * on Tue Mar 22 11:19:29 2005 GMT ++ */ ++ ++#include ++ ++/* ++ * The header consists of the following fields: ++ * uint32_t magic; ++ * uint8_t desc_size; ++ * uint8_t var_size; ++ * uint8_t inc_size; ++ * uint8_t first_var; ++ * uint8_t reserved[8]; ++ * ++ * The size fields contain the number of 32-bit words. ++*/ ++ ++uint32_t sdma_fec_tx_task[] = { ++ /* header */ ++ 0x4243544b, ++ 0x2407070d, ++ 0x00000000, ++ 0x00000000, ++ ++ /* Task descriptors */ ++ 0x8018001b, /* LCD: idx0 = var0; idx0 <= var0; idx0 += inc3 */ ++ 0x60000005, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */ ++ 0x01ccfc0d, /* DRD2B1: var7 = EU3(); EU3(*idx0,var13) */ ++ 0x8082a123, /* LCD: idx0 = var1, idx1 = var5; idx1 <= var4; idx0 += inc4, idx1 += inc3 */ ++ 0x10801418, /* DRD1A: var5 = var3; FN=0 MORE init=4 WS=0 RS=0 */ ++ 0xf88103a4, /* LCDEXT: idx2 = *idx1, idx3 = var2; idx2 < var14; idx2 += inc4, idx3 += inc4 */ ++ 0x801a6024, /* LCD: idx4 = var0; ; idx4 += inc4 */ ++ 0x10001708, /* DRD1A: var5 = idx1; FN=0 MORE init=0 WS=0 RS=0 */ ++ 0x60140002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */ ++ 0x0cccfccf, /* DRD2B1: *idx3 = EU3(); EU3(*idx3,var15) */ ++ 0x991a002c, /* LCD: idx2 = idx2, idx3 = idx4; idx2 once var0; idx2 += inc5, idx3 += inc4 */ ++ 0x70000002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */ ++ 0x024cfc4d, /* DRD2B1: var9 = EU3(); EU3(*idx1,var13) */ ++ 0x60000003, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=3 EXT init=0 WS=0 RS=0 */ ++ 0x0cccf247, /* DRD2B1: *idx3 = EU3(); EU3(var9,var7) */ ++ 0x80004000, /* LCDEXT: idx2 = 0x00000000; ; */ ++ 0xb8c80029, /* LCD: idx3 = *(idx1 + var0000001a); idx3 once var0; idx3 += inc5 */ ++ 0x70000002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */ ++ 0x088cf8d1, /* DRD2B1: idx2 = EU3(); EU3(idx3,var17) */ ++ 0x00002f10, /* DRD1A: var11 = idx2; FN=0 init=0 WS=0 RS=0 */ ++ 0x99198432, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var16; idx2 += inc6, idx3 += inc2 */ ++ 0x008ac398, /* DRD1A: *idx0 = *idx3; FN=0 init=4 WS=1 RS=1 */ ++ 0x80004000, /* LCDEXT: idx2 = 0x00000000; ; */ ++ 0x9999802d, /* LCD: idx3 = idx3; idx3 once var0; idx3 += inc5 */ ++ 0x70000002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */ ++ 0x048cfc53, /* DRD2B1: var18 = EU3(); EU3(*idx1,var19) */ ++ 0x60000008, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=8 EXT init=0 WS=0 RS=0 */ ++ 0x088cf48b, /* DRD2B1: idx2 = EU3(); EU3(var18,var11) */ ++ 0x99198481, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var18; idx2 += inc0, idx3 += inc1 */ ++ 0x009ec398, /* DRD1A: *idx0 = *idx3; FN=0 init=4 WS=3 RS=3 */ ++ 0x991983b2, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var14; idx2 += inc6, idx3 += inc2 */ ++ 0x088ac398, /* DRD1A: *idx0 = *idx3; FN=0 TFD init=4 WS=1 RS=1 */ ++ 0x9919002d, /* LCD: idx2 = idx2; idx2 once var0; idx2 += inc5 */ ++ 0x60000005, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */ ++ 0x0c4cf88e, /* DRD2B1: *idx1 = EU3(); EU3(idx2,var14) */ ++ 0x000001f8, /* NOP */ ++ ++ /* VAR[13]-VAR[19] */ ++ 0x0c000000, ++ 0x40000000, ++ 0x7fff7fff, ++ 0x00000000, ++ 0x00000003, ++ 0x40000004, ++ 0x43ffffff, ++ ++ /* INC[0]-INC[6] */ ++ 0x40000000, ++ 0xe0000000, ++ 0xe0000000, ++ 0xa0000008, ++ 0x20000000, ++ 0x00000000, ++ 0x4000ffff, ++}; +-- +1.4.4.2 + diff --git a/debian/patches/features/powerpc/efika/0022-MPC52xx-PCI-now-working-on-lite5200.-ugly-but-working.txt b/debian/patches/features/powerpc/efika/0022-MPC52xx-PCI-now-working-on-lite5200.-ugly-but-working.txt new file mode 100644 index 000000000..dbf61629f --- /dev/null +++ b/debian/patches/features/powerpc/efika/0022-MPC52xx-PCI-now-working-on-lite5200.-ugly-but-working.txt @@ -0,0 +1,464 @@ +From c4c2f5cb57335b1b47aa8007b0cfce48cc46fa06 Mon Sep 17 00:00:00 2001 +From: Grant Likely +Date: Tue, 21 Nov 2006 14:41:59 -0700 +Subject: [PATCH] [MPC52xx] PCI now working on lite5200... ugly, but working + +Signed-off-by: Grant Likely +--- + arch/powerpc/platforms/52xx/mpc52xx_pci.c | 334 +++++++++++++++++++++++++++++ + arch/powerpc/platforms/52xx/mpc52xx_pci.h | 104 +++++++++ + 2 files changed, 438 insertions(+), 0 deletions(-) + +diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c +new file mode 100644 +index 0000000..07dce3c +--- /dev/null ++++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c +@@ -0,0 +1,334 @@ ++/* ++ * PCI code for the Freescale MPC52xx embedded CPU. ++ * ++ * Copyright (C) 2004 Secret Lab Technologies Ltd. ++ * Grant Likely ++ * Copyright (C) 2004 Sylvain Munaut ++ * ++ * 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. ++ */ ++ ++#define DEBUG ++ ++#include ++#include ++#include "mpc52xx_pci.h" ++#include ++#include ++#include ++ ++ ++/* This macro is defined to activate the workaround for the bug ++ 435 of the MPC5200 (L25R). With it activated, we don't do any ++ 32 bits configuration access during type-1 cycles */ ++#define MPC5200_BUG_435_WORKAROUND ++ ++ ++static int ++mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, ++ int offset, int len, u32 *val) ++{ ++ struct pci_controller *hose = bus->sysdata; ++ u32 value; ++ ++ if (ppc_md.pci_exclude_device) ++ if (ppc_md.pci_exclude_device(bus->number, devfn)) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ out_be32(hose->cfg_addr, ++ (1 << 31) | ++ ((bus->number - hose->bus_offset) << 16) | ++ (devfn << 8) | ++ (offset & 0xfc)); ++ mb(); ++ ++#ifdef MPC5200_BUG_435_WORKAROUND ++ if (bus->number != hose->bus_offset) { ++ switch (len) { ++ case 1: ++ value = in_8(((u8 __iomem *)hose->cfg_data) + ++ (offset & 3)); ++ break; ++ case 2: ++ value = in_le16(((u16 __iomem *)hose->cfg_data) + ++ ((offset>>1) & 1)); ++ break; ++ ++ default: ++ value = in_le16((u16 __iomem *)hose->cfg_data) | ++ (in_le16(((u16 __iomem *)hose->cfg_data) + 1) << 16); ++ break; ++ } ++ } ++ else ++#endif ++ { ++ value = in_le32(hose->cfg_data); ++ ++ if (len != 4) { ++ value >>= ((offset & 0x3) << 3); ++ value &= 0xffffffff >> (32 - (len << 3)); ++ } ++ } ++ ++ *val = value; ++ ++ out_be32(hose->cfg_addr, 0); ++ mb(); ++ ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++static int ++mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, ++ int offset, int len, u32 val) ++{ ++ struct pci_controller *hose = bus->sysdata; ++ u32 value, mask; ++ ++ if (ppc_md.pci_exclude_device) ++ if (ppc_md.pci_exclude_device(bus->number, devfn)) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ out_be32(hose->cfg_addr, ++ (1 << 31) | ++ ((bus->number - hose->bus_offset) << 16) | ++ (devfn << 8) | ++ (offset & 0xfc)); ++ mb(); ++ ++#ifdef MPC5200_BUG_435_WORKAROUND ++ if (bus->number != hose->bus_offset) { ++ switch (len) { ++ case 1: ++ out_8(((u8 __iomem *)hose->cfg_data) + ++ (offset & 3), val); ++ break; ++ case 2: ++ out_le16(((u16 __iomem *)hose->cfg_data) + ++ ((offset>>1) & 1), val); ++ break; ++ ++ default: ++ out_le16((u16 __iomem *)hose->cfg_data, ++ (u16)val); ++ out_le16(((u16 __iomem *)hose->cfg_data) + 1, ++ (u16)(val>>16)); ++ break; ++ } ++ } ++ else ++#endif ++ { ++ if (len != 4) { ++ value = in_le32(hose->cfg_data); ++ ++ offset = (offset & 0x3) << 3; ++ mask = (0xffffffff >> (32 - (len << 3))); ++ mask <<= offset; ++ ++ value &= ~mask; ++ val = value | ((val << offset) & mask); ++ } ++ ++ out_le32(hose->cfg_data, val); ++ } ++ mb(); ++ ++ out_be32(hose->cfg_addr, 0); ++ mb(); ++ ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++static struct pci_ops mpc52xx_pci_ops = { ++ .read = mpc52xx_pci_read_config, ++ .write = mpc52xx_pci_write_config ++}; ++ ++ ++static void __init ++mpc52xx_pci_setup(struct pci_controller *hose, ++ struct mpc52xx_pci __iomem *pci_regs) ++{ ++ struct resource *res; ++ u32 tmp; ++ int iwcr0 = 0, iwcr1 = 0, iwcr2 = 0; ++ ++ pr_debug("mpc52xx_pci_setup()\n"); ++ ++ pr_debug("iw0btar=%x iw1btar=%x iw2btar=%x iwcr=%x\n", ++ in_be32(&pci_regs->iw0btar), in_be32(&pci_regs->iw1btar), ++ in_be32(&pci_regs->iw2btar), in_be32(&pci_regs->iwcr)); ++ pr_debug("tbatr0=%x tbatr1=%x tcr=%x gscr=%x\n", ++ in_be32(&pci_regs->tbatr0), in_be32(&pci_regs->tbatr1), ++ in_be32(&pci_regs->tcr), in_be32(&pci_regs->gscr)); ++ ++ /* Setup control regs */ ++ tmp = in_be32(&pci_regs->scr); ++ tmp |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; ++ out_be32(&pci_regs->scr, tmp); ++ ++ /* Setup windows */ ++ res = &hose->mem_resources[0]; ++ if (res->flags) { ++ pr_debug("mem_resource[0] = {.start=%x, .end=%x, .flags=%lx}\n", ++ res->start, res->end, res->flags); ++ out_be32(&pci_regs->iw0btar, ++ MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start, ++ res->end - res->start + 1)); ++ iwcr0 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM; ++ if (res->flags & IORESOURCE_PREFETCH) ++ iwcr0 |= MPC52xx_PCI_IWCR_READ_MULTI; ++ else ++ iwcr0 |= MPC52xx_PCI_IWCR_READ; ++ } ++ ++ res = &hose->mem_resources[1]; ++ if (res->flags) { ++ pr_debug("mem_resource[1] = {.start=%x, .end=%x, .flags=%lx}\n", ++ res->start, res->end, res->flags); ++ out_be32(&pci_regs->iw1btar, ++ MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start, ++ res->end - res->start + 1)); ++ iwcr1 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM; ++ if (res->flags & IORESOURCE_PREFETCH) ++ iwcr1 |= MPC52xx_PCI_IWCR_READ_MULTI; ++ else ++ iwcr1 |= MPC52xx_PCI_IWCR_READ; ++ } ++ ++ res = &hose->io_resource; ++ if (!res) { ++ printk(KERN_ERR "%s: Didn't find IO resources\n", __FILE__); ++ return; ++ } ++ pr_debug(".io_resource={.start=%x,.end=%x,.flags=%lx} " ++ ".io_base_phys=%lx\n", ++ res->start, res->end, res->flags, hose->io_base_phys); ++ out_be32(&pci_regs->iw2btar, ++ MPC52xx_PCI_IWBTAR_TRANSLATION(hose->io_base_phys, ++ res->start, ++ res->end - res->start + 1)); ++ iwcr2 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_IO; ++ ++ pr_debug("iwcr0=%x iwcr1=%x iwcr2=%x iwcr=%x old_iwcr=%x\n", ++ iwcr0, iwcr1, iwcr2, ++ MPC52xx_PCI_IWCR_PACK(iwcr0, iwcr1, iwcr2), ++ in_be32(&pci_regs->iwcr)); ++ out_be32(&pci_regs->iwcr, MPC52xx_PCI_IWCR_PACK(iwcr0, iwcr1, iwcr2)); ++ ++ out_be32(&pci_regs->tbatr0, ++ MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_IO ); ++ out_be32(&pci_regs->tbatr1, ++ MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_MEM ); ++ ++ out_be32(&pci_regs->tcr, MPC52xx_PCI_TCR_LD); ++ ++ /* Reset the exteral bus ( internal PCI controller is NOT resetted ) */ ++ /* Not necessary and can be a bad thing if for example the bootloader ++ is displaying a splash screen or ... Just left here for ++ documentation purpose if anyone need it */ ++ tmp = in_be32(&pci_regs->gscr); ++#if 0 ++ out_be32(&pci_regs->gscr, tmp | MPC52xx_PCI_GSCR_PR); ++ udelay(50); ++#endif ++ out_be32(&pci_regs->gscr, tmp & ~MPC52xx_PCI_GSCR_PR); ++ ++ pr_debug("iw0btar=%x iw1btar=%x iw2btar=%x iwcr=%x\n", ++ in_be32(&pci_regs->iw0btar), in_be32(&pci_regs->iw1btar), ++ in_be32(&pci_regs->iw2btar), in_be32(&pci_regs->iwcr)); ++ pr_debug("tbatr0=%x tbatr1=%x tcr=%x gscr=%x\n", ++ in_be32(&pci_regs->tbatr0), in_be32(&pci_regs->tbatr1), ++ in_be32(&pci_regs->tcr), in_be32(&pci_regs->gscr)); ++} ++ ++static void ++mpc52xx_pci_fixup_resources(struct pci_dev *dev) ++{ ++ int i; ++ ++ pr_debug("mpc52xx_pci_fixup_resources() %.4x:%.4x\n", ++ dev->vendor, dev->device); ++ ++ /* We don't rely on boot loader for PCI and resets all ++ devices */ ++ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { ++ struct resource *res = &dev->resource[i]; ++ if (res->end > res->start) { /* Only valid resources */ ++ res->end -= res->start; ++ res->start = 0; ++ res->flags |= IORESOURCE_UNSET; ++ } ++ } ++ ++ /* The PCI Host bridge of MPC52xx has a prefetch memory resource ++ fixed to 1Gb. Doesn't fit in the resource system so we remove it */ ++ if ( (dev->vendor == PCI_VENDOR_ID_MOTOROLA) && ++ ( dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200 ++ || dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200B) ) { ++ struct resource *res = &dev->resource[1]; ++ res->start = res->end = res->flags = 0; ++ } ++} ++ ++int __init ++mpc52xx_add_bridge(struct device_node *node) ++{ ++ int len; ++ struct mpc52xx_pci __iomem *pci_regs; ++ struct pci_controller *hose; ++ const int *bus_range; ++ struct resource rsrc; ++ ++ pr_debug("Adding PCI host bridge %s\n", node->full_name); ++ ++ pci_assign_all_buses = 1; ++ ++ if (of_address_to_resource(node, 0, &rsrc) != 0) { ++ printk(KERN_ERR "Can't get %s resources\n", node->full_name); ++ return -EINVAL; ++ } ++ ++ bus_range = get_property(node, "bus-range", &len); ++ if (bus_range == NULL || len < 2 * sizeof(int)) { ++ printk(KERN_WARNING "Can't get bus-range for %s, assume" ++ " bus 0\n", node->full_name); ++ } ++ ++ hose = pcibios_alloc_controller(); ++ if (!hose) ++ return -ENOMEM; ++ ++ ppc_md.pcibios_fixup_resources = mpc52xx_pci_fixup_resources; ++ ++ hose->arch_data = node; ++ hose->set_cfg_type = 1; ++ ++ hose->first_busno = bus_range ? bus_range[0] : 0; ++ hose->last_busno = bus_range ? bus_range[1] : 0xff; ++ ++ hose->bus_offset = 0; ++ hose->ops = &mpc52xx_pci_ops; ++ ++ pci_regs = ioremap(rsrc.start, rsrc.end - rsrc.start + 1); ++ if (!pci_regs) ++ return -ENOMEM; ++ ++ pci_process_bridge_OF_ranges(hose, node, 0); ++ ++ hose->cfg_addr = &pci_regs->car; ++ ++ hose->cfg_data = hose->io_base_virt; ++ hose->io_base_virt = ioremap(hose->io_base_phys, ++ hose->io_resource.end + 1 - ++ hose->io_resource.start); ++ isa_io_base = (unsigned long) hose->io_base_virt; ++ ++ mpc52xx_pci_setup(hose, pci_regs); ++ ++ return 0; ++} +diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.h b/arch/powerpc/platforms/52xx/mpc52xx_pci.h +new file mode 100644 +index 0000000..07a659e +--- /dev/null ++++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.h +@@ -0,0 +1,104 @@ ++/* ++ * PCI Include file the Freescale MPC52xx embedded cpu chips ++ * ++ * Inspired from code written by Dale Farnsworth ++ * for the 2.4 kernel. ++ * ++ * Copyright (C) 2004 Sylvain Munaut ++ * Copyright (C) 2003 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. ++ */ ++ ++#ifndef __SYSLIB_MPC52xx_PCI_H__ ++#define __SYSLIB_MPC52xx_PCI_H__ ++ ++/* ======================================================================== */ ++/* PCI windows config */ ++/* ======================================================================== */ ++ ++#define MPC52xx_PCI_TARGET_IO 0xf0000000 ++#define MPC52xx_PCI_TARGET_MEM 0x00000000 ++ ++ ++/* ======================================================================== */ ++/* Structures mapping & Defines for PCI Unit */ ++/* ======================================================================== */ ++ ++#define MPC52xx_PCI_GSCR_BM 0x40000000 ++#define MPC52xx_PCI_GSCR_PE 0x20000000 ++#define MPC52xx_PCI_GSCR_SE 0x10000000 ++#define MPC52xx_PCI_GSCR_XLB2PCI_MASK 0x07000000 ++#define MPC52xx_PCI_GSCR_XLB2PCI_SHIFT 24 ++#define MPC52xx_PCI_GSCR_IPG2PCI_MASK 0x00070000 ++#define MPC52xx_PCI_GSCR_IPG2PCI_SHIFT 16 ++#define MPC52xx_PCI_GSCR_BME 0x00004000 ++#define MPC52xx_PCI_GSCR_PEE 0x00002000 ++#define MPC52xx_PCI_GSCR_SEE 0x00001000 ++#define MPC52xx_PCI_GSCR_PR 0x00000001 ++ ++ ++#define MPC52xx_PCI_IWBTAR_TRANSLATION(proc_ad,pci_ad,size) \ ++ ( ( (proc_ad) & 0xff000000 ) | \ ++ ( (((size) - 1) >> 8) & 0x00ff0000 ) | \ ++ ( ((pci_ad) >> 16) & 0x0000ff00 ) ) ++ ++#define MPC52xx_PCI_IWCR_PACK(win0,win1,win2) (((win0) << 24) | \ ++ ((win1) << 16) | \ ++ ((win2) << 8)) ++ ++#define MPC52xx_PCI_IWCR_DISABLE 0x0 ++#define MPC52xx_PCI_IWCR_ENABLE 0x1 ++#define MPC52xx_PCI_IWCR_READ 0x0 ++#define MPC52xx_PCI_IWCR_READ_LINE 0x2 ++#define MPC52xx_PCI_IWCR_READ_MULTI 0x4 ++#define MPC52xx_PCI_IWCR_MEM 0x0 ++#define MPC52xx_PCI_IWCR_IO 0x8 ++ ++#define MPC52xx_PCI_TCR_P 0x01000000 ++#define MPC52xx_PCI_TCR_LD 0x00010000 ++ ++#define MPC52xx_PCI_TBATR_DISABLE 0x0 ++#define MPC52xx_PCI_TBATR_ENABLE 0x1 ++ ++ ++#ifndef __ASSEMBLY__ ++ ++struct mpc52xx_pci { ++ u32 idr; /* PCI + 0x00 */ ++ u32 scr; /* PCI + 0x04 */ ++ u32 ccrir; /* PCI + 0x08 */ ++ u32 cr1; /* PCI + 0x0C */ ++ u32 bar0; /* PCI + 0x10 */ ++ u32 bar1; /* PCI + 0x14 */ ++ u8 reserved1[16]; /* PCI + 0x18 */ ++ u32 ccpr; /* PCI + 0x28 */ ++ u32 sid; /* PCI + 0x2C */ ++ u32 erbar; /* PCI + 0x30 */ ++ u32 cpr; /* PCI + 0x34 */ ++ u8 reserved2[4]; /* PCI + 0x38 */ ++ u32 cr2; /* PCI + 0x3C */ ++ u8 reserved3[32]; /* PCI + 0x40 */ ++ u32 gscr; /* PCI + 0x60 */ ++ u32 tbatr0; /* PCI + 0x64 */ ++ u32 tbatr1; /* PCI + 0x68 */ ++ u32 tcr; /* PCI + 0x6C */ ++ u32 iw0btar; /* PCI + 0x70 */ ++ u32 iw1btar; /* PCI + 0x74 */ ++ u32 iw2btar; /* PCI + 0x78 */ ++ u8 reserved4[4]; /* PCI + 0x7C */ ++ u32 iwcr; /* PCI + 0x80 */ ++ u32 icr; /* PCI + 0x84 */ ++ u32 isr; /* PCI + 0x88 */ ++ u32 arb; /* PCI + 0x8C */ ++ u8 reserved5[104]; /* PCI + 0x90 */ ++ u32 car; /* PCI + 0xF8 */ ++ u8 reserved6[4]; /* PCI + 0xFC */ ++}; ++ ++#endif /* __ASSEMBLY__ */ ++ ++ ++#endif /* __SYSLIB_MPC52xx_PCI_H__ */ +-- +1.4.4.2 + diff --git a/debian/patches/features/powerpc/efika/0023-POWERPC-Make-FEC-work-on-the-lite5200.txt b/debian/patches/features/powerpc/efika/0023-POWERPC-Make-FEC-work-on-the-lite5200.txt new file mode 100644 index 000000000..bdbafcb30 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0023-POWERPC-Make-FEC-work-on-the-lite5200.txt @@ -0,0 +1,700 @@ +From 3c687b616fee5d7097e965fce80f8f8b2b6e14cf Mon Sep 17 00:00:00 2001 +From: Grant Likely +Date: Mon, 4 Dec 2006 22:29:03 -0700 +Subject: [PATCH] [POWERPC] Make FEC work on the lite5200 + +This patch may very well break Eth support on the Efika, and it's not +very pretty. But is works well enough for an NFS rootfs. This also +makes major bestcomm changes by removing Efika-specific bestcomm +support and porting the arch/ppc bestcomm support driver which +was posted to linuxppc-embedded about a year ago. + +Signed-off-by: Grant Likely +--- + arch/powerpc/Kconfig | 5 + + arch/powerpc/platforms/52xx/Makefile | 3 + + arch/powerpc/platforms/52xx/bestcomm.c | 98 ++++++++++------------- + arch/powerpc/platforms/52xx/bestcomm.h | 13 ++- + arch/powerpc/platforms/52xx/fec.c | 1 - + arch/powerpc/platforms/52xx/lite5200.c | 9 ++ + drivers/net/fec_mpc52xx/Kconfig | 2 +- + drivers/net/fec_mpc52xx/fec.c | 137 +++++++++++++++++++++++++++---- + drivers/net/fec_mpc52xx/fec_phy.c | 6 ++ + 9 files changed, 196 insertions(+), 78 deletions(-) + +diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig +index 8699dad..23d7d73 100644 +--- a/arch/powerpc/Kconfig ++++ b/arch/powerpc/Kconfig +@@ -429,6 +429,11 @@ config PPC_MPC52xx + bool + default n + ++config PPC_BESTCOMM ++ bool ++ depends on PPC_MPC52xx ++ default y ++ + config PPC_EFIKA + bool "bPlan Efika 5k2. MPC5200B based computer" + depends on PPC_MULTIPLATFORM && PPC32 +diff --git a/arch/powerpc/platforms/52xx/Makefile b/arch/powerpc/platforms/52xx/Makefile +index a46184a..d85ea04 100644 +--- a/arch/powerpc/platforms/52xx/Makefile ++++ b/arch/powerpc/platforms/52xx/Makefile +@@ -3,6 +3,9 @@ + # + ifeq ($(CONFIG_PPC_MERGE),y) + obj-y += mpc52xx_pic.o mpc52xx_common.o ++obj-$(CONFIG_PCI) += mpc52xx_pci.o ++obj-$(CONFIG_PPC_BESTCOMM) += bestcomm.o ++obj-$(CONFIG_FEC_MPC52xx) += sdma_fec_rx_task.o sdma_fec_tx_task.o fec.o + endif + + obj-$(CONFIG_PPC_EFIKA) += efika-setup.o efika-pci.o +diff --git a/arch/powerpc/platforms/52xx/bestcomm.c b/arch/powerpc/platforms/52xx/bestcomm.c +index ef45e02..9935b01 100644 +--- a/arch/powerpc/platforms/52xx/bestcomm.c ++++ b/arch/powerpc/platforms/52xx/bestcomm.c +@@ -16,7 +16,6 @@ + * Andrey Volkov , Varma Electronics Oy + */ + +-#include + #include + #include + #include +@@ -24,17 +23,19 @@ + #include + #include + #include +-#include + + #include + #include + #include ++#include + + #include "bestcomm.h" + +-#define DRIVER_NAME "mpc52xx-sdma" ++#define DRIVER_NAME "mpc52xx-bestcomm" + + struct sdma_io sdma; ++struct device_node *sdma_node; ++struct device_node *sram_node; + + static spinlock_t sdma_lock = SPIN_LOCK_UNLOCKED; + +@@ -42,7 +43,8 @@ static spinlock_t sdma_lock = SPIN_LOCK_UNLOCKED; + void sdma_dump(void) + { + int i; +- printk("** SDMA registers: pa = %08x, va = %08x\n", sdma.base_reg_addr, sdma.io); ++ printk("** SDMA registers: pa = %.8lx, va = %p\n", ++ sdma.base_reg_addr, sdma.io); + printk("** taskBar = %08x\n", sdma.io->taskBar); + printk("** currentPointer = %08x\n", sdma.io->currentPointer); + printk("** endPointer = %08x\n", sdma.io->endPointer); +@@ -254,6 +256,7 @@ struct sdma *sdma_alloc(int queue_size) + } + + s->num_bd = queue_size; ++ s->node = sdma_node; + return s; + } + +@@ -264,29 +267,49 @@ void sdma_free(struct sdma *s) + kfree(s); + } + +-static int __devinit mpc52xx_sdma_probe(struct device *dev) ++static int __init mpc52xx_sdma_init(void) + { +- struct platform_device *pdev = to_platform_device(dev); + int task; + u32 *context; + u32 *fdt; + struct sdma_tdt *tdt; +- struct resource *mem_io, *mem_sram; +- u32 tdt_pa, var_pa, context_pa, fdt_pa; ++ struct resource mem_io, mem_sram; ++ u32 tdt_pa, var_pa, context_pa, fdt_pa; + int ret = -ENODEV; + +- mem_io = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- mem_sram = platform_get_resource(pdev, IORESOURCE_MEM, 1); +- if (!mem_io || !mem_sram) ++ /* Find SDMA registers */ ++ sdma_node = of_find_compatible_node(NULL, "dma-controller", "mpc52xx-bestcomm"); ++ if (!sdma_node) { ++ printk (KERN_ERR DRIVER_NAME ": could not locate SDRAM controller\n"); + goto out; ++ } ++ ++ if ((ret = of_address_to_resource(sdma_node, 0, &mem_io)) != 0) { ++ printk(KERN_ERR "Could not get address of SDMA controller\n"); ++ goto out; ++ } ++ ++ /* Find SRAM location */ ++ sram_node = of_find_compatible_node(NULL, "sram", "mpc52xx-sram"); ++ if (!sram_node) { ++ printk (KERN_ERR DRIVER_NAME ": could not locate SRAM\n"); ++ goto out; ++ } ++ ++ if ((ret = of_address_to_resource(sram_node, 0, &mem_sram)) != 0) { ++ printk(KERN_ERR "Could not get address of SRAM\n"); ++ goto out; ++ } + +- if (!request_mem_region(mem_io->start, mem_io->end - mem_io->start + 1, DRIVER_NAME)) { ++ /* Map register regions */ ++ if (!request_mem_region(mem_io.start, mem_io.end - mem_io.start + 1, ++ DRIVER_NAME)) { + printk(KERN_ERR DRIVER_NAME " - resource unavailable\n"); + goto out; + } +- sdma.base_reg_addr = mem_io->start; ++ sdma.base_reg_addr = mem_io.start; + +- sdma.io = ioremap_nocache(mem_io->start, sizeof(struct mpc52xx_sdma)); ++ sdma.io = ioremap_nocache(mem_io.start, sizeof(struct mpc52xx_sdma)); + + if (!sdma.io ) { + printk(KERN_ERR DRIVER_NAME " - failed to map sdma regs\n"); +@@ -296,14 +319,14 @@ static int __devinit mpc52xx_sdma_probe(struct device *dev) + + SDMA_DUMP_REGS(); + +- sdma.sram_size = mem_sram->end - mem_sram->start + 1; +- if (!request_mem_region(mem_sram->start, sdma.sram_size, DRIVER_NAME)) { ++ sdma.sram_size = mem_sram.end - mem_sram.start + 1; ++ if (!request_mem_region(mem_sram.start, sdma.sram_size, DRIVER_NAME)) { + printk(KERN_ERR DRIVER_NAME " - resource unavailable\n"); + goto req_sram_error; + } + +- sdma.base_sram_addr = mem_sram->start; +- sdma.sram = ioremap_nocache(mem_sram->start, sdma.sram_size); ++ sdma.base_sram_addr = mem_sram.start; ++ sdma.sram = ioremap_nocache(mem_sram.start, sdma.sram_size); + if (!sdma.sram ) { + printk(KERN_ERR DRIVER_NAME " - failed to map sdma sram\n"); + ret = -ENOMEM; +@@ -350,50 +373,17 @@ static int __devinit mpc52xx_sdma_probe(struct device *dev) + return 0; + + map_sram_error: +- release_mem_region(mem_sram->start, sdma.sram_size); ++ release_mem_region(mem_sram.start, sdma.sram_size); + req_sram_error: + iounmap(sdma.io); + map_io_error: +- release_mem_region(mem_io->start, mem_io->end - mem_io->start + 1); ++ release_mem_region(mem_io.start, mem_io.end - mem_io.start + 1); + out: + printk(KERN_ERR "DMA: MPC52xx BestComm init FAILED !!!\n"); + return ret; + } + +- +-static struct device_driver mpc52xx_sdma_driver = { +- .owner = THIS_MODULE, +- .name = DRIVER_NAME, +- .bus = &platform_bus_type, +- .probe = mpc52xx_sdma_probe, +-/* .remove = mpc52xx_sdma_remove, TODO */ +-#ifdef CONFIG_PM +-/* .suspend = mpc52xx_sdma_suspend, TODO */ +-/* .resume = mpc52xx_sdma_resume, TODO */ +-#endif +-}; +- +-static int __init +-mpc52xx_sdma_init(void) +-{ +- printk(KERN_INFO "DMA: MPC52xx BestComm driver\n"); +- return driver_register(&mpc52xx_sdma_driver); +-} +- +-#ifdef MODULE +-static void __exit +-mpc52xx_sdma_exit(void) +-{ +- driver_unregister(&mpc52xx_sdma_driver); +-} +-#endif +- +-#ifndef MODULE +- subsys_initcall(mpc52xx_sdma_init); +-#else +- module_init(mpc52xx_sdma_init); +- module_exit(mpc52xx_sdma_exit); +-#endif ++subsys_initcall(mpc52xx_sdma_init); + + + MODULE_DESCRIPTION("Freescale MPC52xx BestComm DMA"); +diff --git a/arch/powerpc/platforms/52xx/bestcomm.h b/arch/powerpc/platforms/52xx/bestcomm.h +index 14bf397..bd2619d 100644 +--- a/arch/powerpc/platforms/52xx/bestcomm.h ++++ b/arch/powerpc/platforms/52xx/bestcomm.h +@@ -19,6 +19,8 @@ + #ifndef __BESTCOMM_BESTCOMM_H__ + #define __BESTCOMM_BESTCOMM_H__ + ++#include "mpc52xx_pic.h" ++ + /* Buffer Descriptor definitions */ + struct sdma_bd { + u32 status; +@@ -70,6 +72,7 @@ struct sdma { + u16 num_bd; + s16 tasknum; + u32 flags; ++ struct device_node *node; + }; + + #define SDMA_FLAGS_NONE 0x0000 +@@ -116,7 +119,9 @@ struct sdma_tdt { + + static inline void sdma_enable_task(int task) + { +- DPRINTK("***DMA enable task (%d): tdt = %08x\n",task, sdma.tdt); ++ u16 reg; ++ ++ DPRINTK("***DMA enable task (%d): tdt = %p\n",task, sdma.tdt); + DPRINTK("***tdt->start = %08x\n",sdma.tdt[task].start); + DPRINTK("***tdt->stop = %08x\n",sdma.tdt[task].stop); + DPRINTK("***tdt->var = %08x\n",sdma.tdt[task].var); +@@ -127,8 +132,8 @@ static inline void sdma_enable_task(int task) + DPRINTK("***tdt->litbase = %08x\n",sdma.tdt[task].litbase); + DPRINTK("***--------------\n"); + +- u16 reg = in_be16(&sdma.io->tcr[task]); +- DPRINTK("***enable task: &sdma.io->tcr=%08x, reg = %04x\n", &sdma.io->tcr, reg); ++ reg = in_be16(&sdma.io->tcr[task]); ++ DPRINTK("***enable task: &sdma.io->tcr=%p, reg = %04x\n", &sdma.io->tcr, reg); + out_be16(&sdma.io->tcr[task], reg | TASK_ENABLE); + } + +@@ -141,7 +146,7 @@ static inline void sdma_disable_task(int task) + + static inline int sdma_irq(struct sdma *s) + { +- return MPC52xx_SDMA_IRQ_BASE + s->tasknum; ++ return irq_of_parse_and_map(s->node, s->tasknum); + } + + static inline void sdma_enable(struct sdma *s) +diff --git a/arch/powerpc/platforms/52xx/fec.c b/arch/powerpc/platforms/52xx/fec.c +index 8756856..90df6f4 100644 +--- a/arch/powerpc/platforms/52xx/fec.c ++++ b/arch/powerpc/platforms/52xx/fec.c +@@ -16,7 +16,6 @@ + * Andrey Volkov , Varma Electronics Oy + */ + +-#include + #include + #include + #include +diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c +index 0f21bab..f1bbe24 100644 +--- a/arch/powerpc/platforms/52xx/lite5200.c ++++ b/arch/powerpc/platforms/52xx/lite5200.c +@@ -107,6 +107,15 @@ static void __init lite52xx_setup_arch(void) + mpc52xx_setup_cpu(); /* Generic */ + lite52xx_setup_cpu(); /* Platorm specific */ + ++#ifdef CONFIG_PCI ++ np = of_find_node_by_type(np, "pci"); ++ if (np) ++ mpc52xx_add_bridge(np); ++ ++ //ppc_md.pci_swizzle = common_swizzle; ++ //ppc_md.pci_exclude_device = mpc52xx_exclude_device; ++#endif ++ + #ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; +diff --git a/drivers/net/fec_mpc52xx/Kconfig b/drivers/net/fec_mpc52xx/Kconfig +index 098c3fa..b6bce55 100644 +--- a/drivers/net/fec_mpc52xx/Kconfig ++++ b/drivers/net/fec_mpc52xx/Kconfig +@@ -11,7 +11,7 @@ config FEC_MPC52xx + Fast Ethernet Controller + + config USE_MDIO +- bool " Use external Ethernet MII PHY" ++ bool "Use external Ethernet MII PHY" + select MII + depends FEC_MPC52xx + ---help--- +diff --git a/drivers/net/fec_mpc52xx/fec.c b/drivers/net/fec_mpc52xx/fec.c +index b5f1559..894da79 100644 +--- a/drivers/net/fec_mpc52xx/fec.c ++++ b/drivers/net/fec_mpc52xx/fec.c +@@ -30,17 +30,24 @@ + #include + #include + ++#if defined(CONFIG_PPC_MERGE) ++#include ++#include ++#include ++#include ++#else + #include + #include ++#endif + + #include "fec_phy.h" + #include "fec.h" + + #define DRIVER_NAME "mpc52xx-fec" + +-static irqreturn_t fec_interrupt(int, void *, struct pt_regs *); +-static irqreturn_t fec_rx_interrupt(int, void *, struct pt_regs *); +-static irqreturn_t fec_tx_interrupt(int, void *, struct pt_regs *); ++static irqreturn_t fec_interrupt(int, void *); ++static irqreturn_t fec_rx_interrupt(int, void *); ++static irqreturn_t fec_tx_interrupt(int, void *); + static struct net_device_stats *fec_get_stats(struct net_device *); + static void fec_set_multicast_list(struct net_device *dev); + static void fec_reinit(struct net_device *dev); +@@ -233,7 +240,7 @@ static int fec_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) + + /* This handles BestComm transmit task interrupts + */ +-static irqreturn_t fec_tx_interrupt(int irq, void *dev_id, struct pt_regs *regs) ++static irqreturn_t fec_tx_interrupt(int irq, void *dev_id) + { + struct net_device *dev = dev_id; + struct fec_priv *priv = (struct fec_priv *)dev->priv; +@@ -259,7 +266,7 @@ static irqreturn_t fec_tx_interrupt(int irq, void *dev_id, struct pt_regs *regs) + return IRQ_HANDLED; + } + +-static irqreturn_t fec_rx_interrupt(int irq, void *dev_id, struct pt_regs *regs) ++static irqreturn_t fec_rx_interrupt(int irq, void *dev_id) + { + struct net_device *dev = dev_id; + struct fec_priv *priv = (struct fec_priv *)dev->priv; +@@ -316,7 +323,7 @@ static irqreturn_t fec_rx_interrupt(int irq, void *dev_id, struct pt_regs *regs) + return IRQ_HANDLED; + } + +-static irqreturn_t fec_interrupt(int irq, void *dev_id, struct pt_regs *regs) ++static irqreturn_t fec_interrupt(int irq, void *dev_id) + { + struct net_device *dev = (struct net_device *)dev_id; + struct fec_priv *priv = (struct fec_priv *)dev->priv; +@@ -324,13 +331,18 @@ static irqreturn_t fec_interrupt(int irq, void *dev_id, struct pt_regs *regs) + int ievent; + + ievent = in_be32(&fec->ievent); ++ if (!ievent) ++ return IRQ_NONE; ++ + out_be32(&fec->ievent, ievent); /* clear pending events */ + + if (ievent & (FEC_IEVENT_RFIFO_ERROR | FEC_IEVENT_XFIFO_ERROR)) { +- if (ievent & FEC_IEVENT_RFIFO_ERROR) +- printk(KERN_WARNING "FEC_IEVENT_RFIFO_ERROR\n"); +- if (ievent & FEC_IEVENT_XFIFO_ERROR) +- printk(KERN_WARNING "FEC_IEVENT_XFIFO_ERROR\n"); ++ if (net_ratelimit() && (ievent & FEC_IEVENT_RFIFO_ERROR)) ++ printk(KERN_WARNING "FEC_IEVENT_RFIFO_ERROR (%.8x)\n", ++ ievent); ++ if (net_ratelimit() && (ievent & FEC_IEVENT_XFIFO_ERROR)) ++ printk(KERN_WARNING "FEC_IEVENT_XFIFO_ERROR (%.8x)\n", ++ ievent); + fec_reinit(dev); + } + else if (ievent & FEC_IEVENT_MII) +@@ -495,7 +507,9 @@ static void fec_hw_init(struct net_device *dev) + { + struct fec_priv *priv = (struct fec_priv *)dev->priv; + struct mpc52xx_fec *fec = priv->fec; ++#if !defined(CONFIG_PPC_MERGE) + bd_t *bd = (bd_t *) &__res; ++#endif + + out_be32(&fec->op_pause, 0x00010020); + out_be32(&fec->rfifo_cntrl, 0x0f000000); +@@ -507,7 +521,9 @@ static void fec_hw_init(struct net_device *dev) + out_be32(&fec->iaddr1, 0x00000000); /* No individual filter */ + out_be32(&fec->iaddr2, 0x00000000); /* No individual filter */ + ++#if !defined(CONFIG_PPC_MERGE) + priv->phy_speed = ((bd->bi_ipbfreq >> 20) / 5) << 1; ++#endif + + fec_restart(dev, 0); /* always use half duplex mode only */ + /* +@@ -522,7 +538,6 @@ static void fec_reinit(struct net_device *dev) + { + struct fec_priv *priv = (struct fec_priv *)dev->priv; + struct mpc52xx_fec *fec = priv->fec; +- static void fec_update_stat(struct net_device *); + + netif_stop_queue(dev); + out_be32(&fec->imask, 0x0); +@@ -551,19 +566,38 @@ static void fec_reinit(struct net_device *dev) + /* Platform Driver */ + /* ======================================================================== */ + ++#if defined(CONFIG_PPC_MERGE) ++static int __devinit ++mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match) ++#else + static int __devinit + mpc52xx_fec_probe(struct device *dev) ++#endif + { + int ret; ++#if defined(CONFIG_PPC_MERGE) ++ int rv; ++ struct resource __mem; ++ struct resource *mem = &__mem; ++#else + struct platform_device *pdev = to_platform_device(dev); ++ struct resource *mem; ++#endif + struct net_device *ndev; + struct fec_priv *priv = NULL; +- struct resource *mem; + + volatile int dbg=0; + while(dbg) + __asm("nop"); + /* Reserve FEC control zone */ ++#if defined(CONFIG_PPC_MERGE) ++ rv = of_address_to_resource(op->node, 0, mem); ++ if (rv) { ++ printk(KERN_ERR DRIVER_NAME ": " ++ "Error while parsing device node resource\n" ); ++ return rv; ++ } ++#else + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if ((mem->end - mem->start + 1) != sizeof(struct mpc52xx_fec)) { + printk(KERN_ERR DRIVER_NAME +@@ -571,7 +605,8 @@ mpc52xx_fec_probe(struct device *dev) + mem->end - mem->start + 1, sizeof(struct mpc52xx_fec)); + return -EINVAL; + } +- ++#endif ++ + if (!request_mem_region(mem->start, sizeof(struct mpc52xx_fec), + DRIVER_NAME)) + return -EBUSY; +@@ -579,6 +614,8 @@ mpc52xx_fec_probe(struct device *dev) + /* Get the ether ndev & it's private zone */ + ndev = alloc_etherdev(sizeof(struct fec_priv)); + if (!ndev) { ++ printk(KERN_ERR DRIVER_NAME ": " ++ "Can not allocate the ethernet device\n" ); + ret = -ENOMEM; + goto probe_error; + } +@@ -609,6 +646,8 @@ mpc52xx_fec_probe(struct device *dev) + ioremap(mem->start, sizeof(struct mpc52xx_fec)); + + if (!priv->fec) { ++ printk(KERN_ERR DRIVER_NAME ": " ++ "Can not remap IO memory at 0x%8.8x\n", mem->start ); + ret = -ENOMEM; + goto probe_error; + } +@@ -618,6 +657,8 @@ mpc52xx_fec_probe(struct device *dev) + priv->tx_sdma = sdma_alloc(FEC_TX_NUM_BD); + + if (!priv->rx_sdma || !priv->tx_sdma) { ++ printk(KERN_ERR DRIVER_NAME ": " ++ "Can not init SDMA tasks\n" ); + ret = -ENOMEM; + goto probe_error; + } +@@ -631,8 +672,13 @@ mpc52xx_fec_probe(struct device *dev) + goto probe_error; + + /* Get the IRQ we need one by one */ +- /* Control */ ++ /* Control */ ++#if defined(CONFIG_PPC_MERGE) ++ ndev->irq = irq_of_parse_and_map(op->node, 0); ++#else + ndev->irq = platform_get_irq(pdev, 0); ++#endif ++ + if (request_irq(ndev->irq, &fec_interrupt, SA_INTERRUPT, + DRIVER_NAME "_ctrl", ndev)) { + printk(KERN_ERR DRIVER_NAME ": ctrl interrupt request failed\n"); +@@ -641,26 +687,32 @@ mpc52xx_fec_probe(struct device *dev) + goto probe_error; + } + +- /* RX */ ++ /* RX */ + priv->r_irq = sdma_irq(priv->rx_sdma); + if (request_irq(priv->r_irq, &fec_rx_interrupt, SA_INTERRUPT, + DRIVER_NAME "_rx", ndev)) { +- printk(KERN_ERR DRIVER_NAME ": rx interrupt request failed\n"); ++ printk(KERN_ERR DRIVER_NAME ": rx request_irq(0x%x) failed\n", ++ priv->r_irq); + ret = -EBUSY; + priv->r_irq = -1; /* Don't try to free it */ + goto probe_error; + } + +- /* TX */ ++ /* TX */ + priv->t_irq = sdma_irq(priv->tx_sdma); + if (request_irq(priv->t_irq, &fec_tx_interrupt, SA_INTERRUPT, + DRIVER_NAME "_tx", ndev)) { +- printk(KERN_ERR DRIVER_NAME ": tx interrupt request failed\n"); ++ printk(KERN_ERR DRIVER_NAME ": tx request_irq(0x%x) failed\n", ++ priv->t_irq); + ret = -EBUSY; + priv->t_irq = -1; /* Don't try to free it */ + goto probe_error; + } + ++#if defined(CONFIG_PPC_MERGE) ++ priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1; ++#endif ++ + /* MAC address init */ + if (memcmp(mpc52xx_fec_mac_addr, null_mac, 6) != 0) + memcpy(ndev->dev_addr, mpc52xx_fec_mac_addr, 6); +@@ -679,7 +731,11 @@ mpc52xx_fec_probe(struct device *dev) + fec_mii_init(ndev); + + /* We're done ! */ ++#if defined(CONFIG_PPC_MERGE) ++ dev_set_drvdata(&op->dev, ndev); ++#else + dev_set_drvdata(dev, ndev); ++#endif + + return 0; + +@@ -705,13 +761,22 @@ probe_error: + return ret; + } + ++#if defined(CONFIG_PPC_MERGE) ++static int ++mpc52xx_fec_remove(struct of_device *op) ++#else + static int + mpc52xx_fec_remove(struct device *dev) ++#endif + { + struct net_device *ndev; + struct fec_priv *priv; + ++#if defined(CONFIG_PPC_MERGE) ++ ndev = (struct net_device *) dev_get_drvdata(&op->dev); ++#else + ndev = (struct net_device *) dev_get_drvdata(dev); ++#endif + if (!ndev) + return 0; + priv = (struct fec_priv *) ndev->priv; +@@ -728,10 +793,37 @@ mpc52xx_fec_remove(struct device *dev) + + free_netdev(ndev); + ++#if defined(CONFIG_PPC_MERGE) ++ dev_set_drvdata(&op->dev, NULL); ++#else + dev_set_drvdata(dev, NULL); ++#endif + return 0; + } + ++#if defined(CONFIG_PPC_MERGE) ++static struct of_device_id mpc52xx_fec_of_match[] = { ++ { .compatible = "mpc5200-ethernet", }, ++ { .compatible = "mpc52xx-fec", }, ++ {}, ++}; ++ ++static struct of_platform_driver mpc52xx_fec_driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ .match_table = mpc52xx_fec_of_match, ++ .probe = mpc52xx_fec_probe, ++ .remove = mpc52xx_fec_remove, ++#ifdef CONFIG_PM ++/* .suspend = mpc52xx_fec_suspend, TODO */ ++/* .resume = mpc52xx_fec_resume, TODO */ ++#endif ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ }, ++}; ++#else + static struct device_driver mpc52xx_fec_driver = { + .name = DRIVER_NAME, + .bus = &platform_bus_type, +@@ -742,6 +834,7 @@ static struct device_driver mpc52xx_fec_driver = { + /* .resume = mpc52xx_fec_resume, TODO */ + #endif + }; ++#endif + + /* ======================================================================== */ + /* Module */ +@@ -750,13 +843,21 @@ static struct device_driver mpc52xx_fec_driver = { + static int __init + mpc52xx_fec_init(void) + { ++#if defined(CONFIG_PPC_MERGE) ++ return of_register_platform_driver(&mpc52xx_fec_driver); ++#else + return driver_register(&mpc52xx_fec_driver); ++#endif + } + + static void __exit + mpc52xx_fec_exit(void) + { ++#if defined(CONFIG_PPC_MERGE) ++ of_unregister_platform_driver(&mpc52xx_fec_driver); ++#else + driver_unregister(&mpc52xx_fec_driver); ++#endif + } + + +diff --git a/drivers/net/fec_mpc52xx/fec_phy.c b/drivers/net/fec_mpc52xx/fec_phy.c +index 2a287de..25e0409 100644 +--- a/drivers/net/fec_mpc52xx/fec_phy.c ++++ b/drivers/net/fec_mpc52xx/fec_phy.c +@@ -20,8 +20,14 @@ + #include + #include + #include ++ ++#ifdef CONFIG_PPC_MERGE ++#include ++#else + #include + #include ++#endif ++ + #include "fec_phy.h" + #include "fec.h" + +-- +1.4.4.2 + diff --git a/debian/patches/features/powerpc/efika/0024-Add-missing-function-prototype.txt b/debian/patches/features/powerpc/efika/0024-Add-missing-function-prototype.txt new file mode 100644 index 000000000..2fb1a495b --- /dev/null +++ b/debian/patches/features/powerpc/efika/0024-Add-missing-function-prototype.txt @@ -0,0 +1,26 @@ +From 4ad1395745f590eba1b5220c8dd3ca6541f49db7 Mon Sep 17 00:00:00 2001 +From: Grant Likely +Date: Mon, 4 Dec 2006 22:55:49 -0700 +Subject: [PATCH] Add missing function prototype + +Signed-off-by: Grant Likely +--- + include/asm-powerpc/mpc52xx.h | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/include/asm-powerpc/mpc52xx.h b/include/asm-powerpc/mpc52xx.h +index 4560d72..7afd5bf 100644 +--- a/include/asm-powerpc/mpc52xx.h ++++ b/include/asm-powerpc/mpc52xx.h +@@ -249,6 +249,8 @@ extern void mpc52xx_declare_of_platform_devices(void); + extern void mpc52xx_init_irq(void); + extern unsigned int mpc52xx_get_irq(void); + ++extern int __init mpc52xx_add_bridge(struct device_node *node); ++ + #endif /* __ASSEMBLY__ */ + + #endif /* __ASM_POWERPC_MPC52xx_H__ */ +-- +1.4.4.2 + diff --git a/debian/patches/features/powerpc/efika/0009-Added-RTAS-support-for-32bit-PowerPC.diff b/debian/patches/features/powerpc/efika/0025-POWERPC-Misc-EFIKA-fixups-for-rtas-chrp.txt similarity index 67% rename from debian/patches/features/powerpc/efika/0009-Added-RTAS-support-for-32bit-PowerPC.diff rename to debian/patches/features/powerpc/efika/0025-POWERPC-Misc-EFIKA-fixups-for-rtas-chrp.txt index 137ed5f03..8f39c3a3d 100644 --- a/debian/patches/features/powerpc/efika/0009-Added-RTAS-support-for-32bit-PowerPC.diff +++ b/debian/patches/features/powerpc/efika/0025-POWERPC-Misc-EFIKA-fixups-for-rtas-chrp.txt @@ -1,19 +1,19 @@ -From 6d3cbf9a4549928be8ed15cf6a3576c217723895 Mon Sep 17 00:00:00 2001 -From: Nicolas DET -Date: Fri, 24 Nov 2006 13:22:22 +0100 -Subject: [PATCH] Added RTAS support for 32bit PowerPC +From 95f80c44731c46261b0ba334b35ee803f21ef60b Mon Sep 17 00:00:00 2001 +From: Grant Likely +Date: Mon, 4 Dec 2006 23:01:13 -0700 +Subject: [PATCH] [POWERPC] Misc EFIKA fixups for rtas/chrp -Signed-off-by: Nicolas DET --- - arch/powerpc/kernel/proc_ppc64.c | 9 --------- - arch/powerpc/kernel/rtas-proc.c | 36 ++++++++++++++++++++++++++---------- - 2 files changed, 26 insertions(+), 19 deletions(-) + arch/powerpc/kernel/proc_ppc64.c | 9 -------- + arch/powerpc/kernel/rtas-proc.c | 36 +++++++++++++++++++++++++--------- + arch/powerpc/platforms/chrp/setup.c | 9 ++++++++ + 3 files changed, 35 insertions(+), 19 deletions(-) diff --git a/arch/powerpc/kernel/proc_ppc64.c b/arch/powerpc/kernel/proc_ppc64.c -index f598cb5..9b9c32d 100644 +index dd7001c..fa54220 100644 --- a/arch/powerpc/kernel/proc_ppc64.c +++ b/arch/powerpc/kernel/proc_ppc64.c -@@ -51,15 +51,6 @@ static int __init proc_ppc64_create(void +@@ -51,15 +51,6 @@ static int __init proc_ppc64_create(void) if (!root) return 1; @@ -33,7 +33,7 @@ diff --git a/arch/powerpc/kernel/rtas-proc.c b/arch/powerpc/kernel/rtas-proc.c index 2fe82ab..4c06c32 100644 --- a/arch/powerpc/kernel/rtas-proc.c +++ b/arch/powerpc/kernel/rtas-proc.c -@@ -253,43 +253,59 @@ static void get_location_code(struct seq +@@ -253,43 +253,59 @@ static void get_location_code(struct seq_file *m, static void check_location_string(struct seq_file *m, const char *c); static void check_location(struct seq_file *m, const char *c); @@ -103,6 +103,31 @@ index 2fe82ab..4c06c32 100644 if (entry) entry->proc_fops = &ppc_rtas_rmo_buf_ops; +diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c +index e1f51d4..ec4515c 100644 +--- a/arch/powerpc/platforms/chrp/setup.c ++++ b/arch/powerpc/platforms/chrp/setup.c +@@ -580,11 +580,20 @@ static int __init chrp_probe(void) + { + char *dtype = of_get_flat_dt_prop(of_get_flat_dt_root(), + "device_type", NULL); ++ ++ char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), ++ "model", NULL); + if (dtype == NULL) + return 0; + if (strcmp(dtype, "chrp")) + return 0; + ++ /* ++ * Filter out efika because it has its own platform ++ */ ++ if (model && (strcmp(model, "EFIKA5K2") == 0) ) ++ return 0; ++ + ISA_DMA_THRESHOLD = ~0L; + DMA_MODE_READ = 0x44; + DMA_MODE_WRITE = 0x48; -- -1.4.3.2 +1.4.4.2 diff --git a/debian/patches/features/powerpc/efika/0026-POWERPC-Cleanup-mpc52xx-PCI-support.txt b/debian/patches/features/powerpc/efika/0026-POWERPC-Cleanup-mpc52xx-PCI-support.txt new file mode 100644 index 000000000..3119060f2 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0026-POWERPC-Cleanup-mpc52xx-PCI-support.txt @@ -0,0 +1,911 @@ +From 78aaa3476bf62a50d85a9753bf1ef82fd296ca73 Mon Sep 17 00:00:00 2001 +From: Grant Likely +Date: Mon, 11 Dec 2006 22:41:49 -0700 +Subject: [PATCH] [POWERPC] Cleanup mpc52xx PCI support + +Signed-off-by: Grant Likely +--- + arch/powerpc/Kconfig | 17 ++- + arch/powerpc/platforms/52xx/mpc52xx_pci.c | 334 ------------------------ + arch/powerpc/platforms/52xx/mpc52xx_pci.h | 104 -------- + arch/powerpc/platforms/52xx/pci.c | 404 +++++++++++++++++++++++++++++ + 4 files changed, 420 insertions(+), 439 deletions(-) + +diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig +index 23d7d73..ec17225 100644 +--- a/arch/powerpc/Kconfig ++++ b/arch/powerpc/Kconfig +@@ -429,6 +429,21 @@ config PPC_MPC52xx + bool + default n + ++config PPC_MPC5200 ++ bool ++ select PPC_MPC52xx ++ default n ++ ++config PPC_MPC5200_BUGFIX ++ bool "MPC5200 (L25R) bugfix support" ++ depends on PPC_MPC5200 ++ default n ++ help ++ Enable workarounds for original MPC5200 errata. This is not required ++ for MPC5200B based boards. ++ ++ It is safe to say 'Y' here ++ + config PPC_BESTCOMM + bool + depends on PPC_MPC52xx +@@ -446,7 +461,7 @@ config PPC_EFIKA + config PPC_LITE5200 + bool "Freescale Lite5200 Eval Board" + depends on PPC_MULTIPLATFORM && PPC32 +- select PPC_MPC52xx ++ select PPC_MPC5200 + default n + + config PPC_PMAC +diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c +deleted file mode 100644 +index 07dce3c..0000000 +--- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c ++++ /dev/null +@@ -1,334 +0,0 @@ +-/* +- * PCI code for the Freescale MPC52xx embedded CPU. +- * +- * Copyright (C) 2004 Secret Lab Technologies Ltd. +- * Grant Likely +- * Copyright (C) 2004 Sylvain Munaut +- * +- * 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. +- */ +- +-#define DEBUG +- +-#include +-#include +-#include "mpc52xx_pci.h" +-#include +-#include +-#include +- +- +-/* This macro is defined to activate the workaround for the bug +- 435 of the MPC5200 (L25R). With it activated, we don't do any +- 32 bits configuration access during type-1 cycles */ +-#define MPC5200_BUG_435_WORKAROUND +- +- +-static int +-mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, +- int offset, int len, u32 *val) +-{ +- struct pci_controller *hose = bus->sysdata; +- u32 value; +- +- if (ppc_md.pci_exclude_device) +- if (ppc_md.pci_exclude_device(bus->number, devfn)) +- return PCIBIOS_DEVICE_NOT_FOUND; +- +- out_be32(hose->cfg_addr, +- (1 << 31) | +- ((bus->number - hose->bus_offset) << 16) | +- (devfn << 8) | +- (offset & 0xfc)); +- mb(); +- +-#ifdef MPC5200_BUG_435_WORKAROUND +- if (bus->number != hose->bus_offset) { +- switch (len) { +- case 1: +- value = in_8(((u8 __iomem *)hose->cfg_data) + +- (offset & 3)); +- break; +- case 2: +- value = in_le16(((u16 __iomem *)hose->cfg_data) + +- ((offset>>1) & 1)); +- break; +- +- default: +- value = in_le16((u16 __iomem *)hose->cfg_data) | +- (in_le16(((u16 __iomem *)hose->cfg_data) + 1) << 16); +- break; +- } +- } +- else +-#endif +- { +- value = in_le32(hose->cfg_data); +- +- if (len != 4) { +- value >>= ((offset & 0x3) << 3); +- value &= 0xffffffff >> (32 - (len << 3)); +- } +- } +- +- *val = value; +- +- out_be32(hose->cfg_addr, 0); +- mb(); +- +- return PCIBIOS_SUCCESSFUL; +-} +- +-static int +-mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, +- int offset, int len, u32 val) +-{ +- struct pci_controller *hose = bus->sysdata; +- u32 value, mask; +- +- if (ppc_md.pci_exclude_device) +- if (ppc_md.pci_exclude_device(bus->number, devfn)) +- return PCIBIOS_DEVICE_NOT_FOUND; +- +- out_be32(hose->cfg_addr, +- (1 << 31) | +- ((bus->number - hose->bus_offset) << 16) | +- (devfn << 8) | +- (offset & 0xfc)); +- mb(); +- +-#ifdef MPC5200_BUG_435_WORKAROUND +- if (bus->number != hose->bus_offset) { +- switch (len) { +- case 1: +- out_8(((u8 __iomem *)hose->cfg_data) + +- (offset & 3), val); +- break; +- case 2: +- out_le16(((u16 __iomem *)hose->cfg_data) + +- ((offset>>1) & 1), val); +- break; +- +- default: +- out_le16((u16 __iomem *)hose->cfg_data, +- (u16)val); +- out_le16(((u16 __iomem *)hose->cfg_data) + 1, +- (u16)(val>>16)); +- break; +- } +- } +- else +-#endif +- { +- if (len != 4) { +- value = in_le32(hose->cfg_data); +- +- offset = (offset & 0x3) << 3; +- mask = (0xffffffff >> (32 - (len << 3))); +- mask <<= offset; +- +- value &= ~mask; +- val = value | ((val << offset) & mask); +- } +- +- out_le32(hose->cfg_data, val); +- } +- mb(); +- +- out_be32(hose->cfg_addr, 0); +- mb(); +- +- return PCIBIOS_SUCCESSFUL; +-} +- +-static struct pci_ops mpc52xx_pci_ops = { +- .read = mpc52xx_pci_read_config, +- .write = mpc52xx_pci_write_config +-}; +- +- +-static void __init +-mpc52xx_pci_setup(struct pci_controller *hose, +- struct mpc52xx_pci __iomem *pci_regs) +-{ +- struct resource *res; +- u32 tmp; +- int iwcr0 = 0, iwcr1 = 0, iwcr2 = 0; +- +- pr_debug("mpc52xx_pci_setup()\n"); +- +- pr_debug("iw0btar=%x iw1btar=%x iw2btar=%x iwcr=%x\n", +- in_be32(&pci_regs->iw0btar), in_be32(&pci_regs->iw1btar), +- in_be32(&pci_regs->iw2btar), in_be32(&pci_regs->iwcr)); +- pr_debug("tbatr0=%x tbatr1=%x tcr=%x gscr=%x\n", +- in_be32(&pci_regs->tbatr0), in_be32(&pci_regs->tbatr1), +- in_be32(&pci_regs->tcr), in_be32(&pci_regs->gscr)); +- +- /* Setup control regs */ +- tmp = in_be32(&pci_regs->scr); +- tmp |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; +- out_be32(&pci_regs->scr, tmp); +- +- /* Setup windows */ +- res = &hose->mem_resources[0]; +- if (res->flags) { +- pr_debug("mem_resource[0] = {.start=%x, .end=%x, .flags=%lx}\n", +- res->start, res->end, res->flags); +- out_be32(&pci_regs->iw0btar, +- MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start, +- res->end - res->start + 1)); +- iwcr0 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM; +- if (res->flags & IORESOURCE_PREFETCH) +- iwcr0 |= MPC52xx_PCI_IWCR_READ_MULTI; +- else +- iwcr0 |= MPC52xx_PCI_IWCR_READ; +- } +- +- res = &hose->mem_resources[1]; +- if (res->flags) { +- pr_debug("mem_resource[1] = {.start=%x, .end=%x, .flags=%lx}\n", +- res->start, res->end, res->flags); +- out_be32(&pci_regs->iw1btar, +- MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start, +- res->end - res->start + 1)); +- iwcr1 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM; +- if (res->flags & IORESOURCE_PREFETCH) +- iwcr1 |= MPC52xx_PCI_IWCR_READ_MULTI; +- else +- iwcr1 |= MPC52xx_PCI_IWCR_READ; +- } +- +- res = &hose->io_resource; +- if (!res) { +- printk(KERN_ERR "%s: Didn't find IO resources\n", __FILE__); +- return; +- } +- pr_debug(".io_resource={.start=%x,.end=%x,.flags=%lx} " +- ".io_base_phys=%lx\n", +- res->start, res->end, res->flags, hose->io_base_phys); +- out_be32(&pci_regs->iw2btar, +- MPC52xx_PCI_IWBTAR_TRANSLATION(hose->io_base_phys, +- res->start, +- res->end - res->start + 1)); +- iwcr2 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_IO; +- +- pr_debug("iwcr0=%x iwcr1=%x iwcr2=%x iwcr=%x old_iwcr=%x\n", +- iwcr0, iwcr1, iwcr2, +- MPC52xx_PCI_IWCR_PACK(iwcr0, iwcr1, iwcr2), +- in_be32(&pci_regs->iwcr)); +- out_be32(&pci_regs->iwcr, MPC52xx_PCI_IWCR_PACK(iwcr0, iwcr1, iwcr2)); +- +- out_be32(&pci_regs->tbatr0, +- MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_IO ); +- out_be32(&pci_regs->tbatr1, +- MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_MEM ); +- +- out_be32(&pci_regs->tcr, MPC52xx_PCI_TCR_LD); +- +- /* Reset the exteral bus ( internal PCI controller is NOT resetted ) */ +- /* Not necessary and can be a bad thing if for example the bootloader +- is displaying a splash screen or ... Just left here for +- documentation purpose if anyone need it */ +- tmp = in_be32(&pci_regs->gscr); +-#if 0 +- out_be32(&pci_regs->gscr, tmp | MPC52xx_PCI_GSCR_PR); +- udelay(50); +-#endif +- out_be32(&pci_regs->gscr, tmp & ~MPC52xx_PCI_GSCR_PR); +- +- pr_debug("iw0btar=%x iw1btar=%x iw2btar=%x iwcr=%x\n", +- in_be32(&pci_regs->iw0btar), in_be32(&pci_regs->iw1btar), +- in_be32(&pci_regs->iw2btar), in_be32(&pci_regs->iwcr)); +- pr_debug("tbatr0=%x tbatr1=%x tcr=%x gscr=%x\n", +- in_be32(&pci_regs->tbatr0), in_be32(&pci_regs->tbatr1), +- in_be32(&pci_regs->tcr), in_be32(&pci_regs->gscr)); +-} +- +-static void +-mpc52xx_pci_fixup_resources(struct pci_dev *dev) +-{ +- int i; +- +- pr_debug("mpc52xx_pci_fixup_resources() %.4x:%.4x\n", +- dev->vendor, dev->device); +- +- /* We don't rely on boot loader for PCI and resets all +- devices */ +- for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { +- struct resource *res = &dev->resource[i]; +- if (res->end > res->start) { /* Only valid resources */ +- res->end -= res->start; +- res->start = 0; +- res->flags |= IORESOURCE_UNSET; +- } +- } +- +- /* The PCI Host bridge of MPC52xx has a prefetch memory resource +- fixed to 1Gb. Doesn't fit in the resource system so we remove it */ +- if ( (dev->vendor == PCI_VENDOR_ID_MOTOROLA) && +- ( dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200 +- || dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200B) ) { +- struct resource *res = &dev->resource[1]; +- res->start = res->end = res->flags = 0; +- } +-} +- +-int __init +-mpc52xx_add_bridge(struct device_node *node) +-{ +- int len; +- struct mpc52xx_pci __iomem *pci_regs; +- struct pci_controller *hose; +- const int *bus_range; +- struct resource rsrc; +- +- pr_debug("Adding PCI host bridge %s\n", node->full_name); +- +- pci_assign_all_buses = 1; +- +- if (of_address_to_resource(node, 0, &rsrc) != 0) { +- printk(KERN_ERR "Can't get %s resources\n", node->full_name); +- return -EINVAL; +- } +- +- bus_range = get_property(node, "bus-range", &len); +- if (bus_range == NULL || len < 2 * sizeof(int)) { +- printk(KERN_WARNING "Can't get bus-range for %s, assume" +- " bus 0\n", node->full_name); +- } +- +- hose = pcibios_alloc_controller(); +- if (!hose) +- return -ENOMEM; +- +- ppc_md.pcibios_fixup_resources = mpc52xx_pci_fixup_resources; +- +- hose->arch_data = node; +- hose->set_cfg_type = 1; +- +- hose->first_busno = bus_range ? bus_range[0] : 0; +- hose->last_busno = bus_range ? bus_range[1] : 0xff; +- +- hose->bus_offset = 0; +- hose->ops = &mpc52xx_pci_ops; +- +- pci_regs = ioremap(rsrc.start, rsrc.end - rsrc.start + 1); +- if (!pci_regs) +- return -ENOMEM; +- +- pci_process_bridge_OF_ranges(hose, node, 0); +- +- hose->cfg_addr = &pci_regs->car; +- +- hose->cfg_data = hose->io_base_virt; +- hose->io_base_virt = ioremap(hose->io_base_phys, +- hose->io_resource.end + 1 - +- hose->io_resource.start); +- isa_io_base = (unsigned long) hose->io_base_virt; +- +- mpc52xx_pci_setup(hose, pci_regs); +- +- return 0; +-} +diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.h b/arch/powerpc/platforms/52xx/mpc52xx_pci.h +deleted file mode 100644 +index 07a659e..0000000 +--- a/arch/powerpc/platforms/52xx/mpc52xx_pci.h ++++ /dev/null +@@ -1,104 +0,0 @@ +-/* +- * PCI Include file the Freescale MPC52xx embedded cpu chips +- * +- * Inspired from code written by Dale Farnsworth +- * for the 2.4 kernel. +- * +- * Copyright (C) 2004 Sylvain Munaut +- * Copyright (C) 2003 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. +- */ +- +-#ifndef __SYSLIB_MPC52xx_PCI_H__ +-#define __SYSLIB_MPC52xx_PCI_H__ +- +-/* ======================================================================== */ +-/* PCI windows config */ +-/* ======================================================================== */ +- +-#define MPC52xx_PCI_TARGET_IO 0xf0000000 +-#define MPC52xx_PCI_TARGET_MEM 0x00000000 +- +- +-/* ======================================================================== */ +-/* Structures mapping & Defines for PCI Unit */ +-/* ======================================================================== */ +- +-#define MPC52xx_PCI_GSCR_BM 0x40000000 +-#define MPC52xx_PCI_GSCR_PE 0x20000000 +-#define MPC52xx_PCI_GSCR_SE 0x10000000 +-#define MPC52xx_PCI_GSCR_XLB2PCI_MASK 0x07000000 +-#define MPC52xx_PCI_GSCR_XLB2PCI_SHIFT 24 +-#define MPC52xx_PCI_GSCR_IPG2PCI_MASK 0x00070000 +-#define MPC52xx_PCI_GSCR_IPG2PCI_SHIFT 16 +-#define MPC52xx_PCI_GSCR_BME 0x00004000 +-#define MPC52xx_PCI_GSCR_PEE 0x00002000 +-#define MPC52xx_PCI_GSCR_SEE 0x00001000 +-#define MPC52xx_PCI_GSCR_PR 0x00000001 +- +- +-#define MPC52xx_PCI_IWBTAR_TRANSLATION(proc_ad,pci_ad,size) \ +- ( ( (proc_ad) & 0xff000000 ) | \ +- ( (((size) - 1) >> 8) & 0x00ff0000 ) | \ +- ( ((pci_ad) >> 16) & 0x0000ff00 ) ) +- +-#define MPC52xx_PCI_IWCR_PACK(win0,win1,win2) (((win0) << 24) | \ +- ((win1) << 16) | \ +- ((win2) << 8)) +- +-#define MPC52xx_PCI_IWCR_DISABLE 0x0 +-#define MPC52xx_PCI_IWCR_ENABLE 0x1 +-#define MPC52xx_PCI_IWCR_READ 0x0 +-#define MPC52xx_PCI_IWCR_READ_LINE 0x2 +-#define MPC52xx_PCI_IWCR_READ_MULTI 0x4 +-#define MPC52xx_PCI_IWCR_MEM 0x0 +-#define MPC52xx_PCI_IWCR_IO 0x8 +- +-#define MPC52xx_PCI_TCR_P 0x01000000 +-#define MPC52xx_PCI_TCR_LD 0x00010000 +- +-#define MPC52xx_PCI_TBATR_DISABLE 0x0 +-#define MPC52xx_PCI_TBATR_ENABLE 0x1 +- +- +-#ifndef __ASSEMBLY__ +- +-struct mpc52xx_pci { +- u32 idr; /* PCI + 0x00 */ +- u32 scr; /* PCI + 0x04 */ +- u32 ccrir; /* PCI + 0x08 */ +- u32 cr1; /* PCI + 0x0C */ +- u32 bar0; /* PCI + 0x10 */ +- u32 bar1; /* PCI + 0x14 */ +- u8 reserved1[16]; /* PCI + 0x18 */ +- u32 ccpr; /* PCI + 0x28 */ +- u32 sid; /* PCI + 0x2C */ +- u32 erbar; /* PCI + 0x30 */ +- u32 cpr; /* PCI + 0x34 */ +- u8 reserved2[4]; /* PCI + 0x38 */ +- u32 cr2; /* PCI + 0x3C */ +- u8 reserved3[32]; /* PCI + 0x40 */ +- u32 gscr; /* PCI + 0x60 */ +- u32 tbatr0; /* PCI + 0x64 */ +- u32 tbatr1; /* PCI + 0x68 */ +- u32 tcr; /* PCI + 0x6C */ +- u32 iw0btar; /* PCI + 0x70 */ +- u32 iw1btar; /* PCI + 0x74 */ +- u32 iw2btar; /* PCI + 0x78 */ +- u8 reserved4[4]; /* PCI + 0x7C */ +- u32 iwcr; /* PCI + 0x80 */ +- u32 icr; /* PCI + 0x84 */ +- u32 isr; /* PCI + 0x88 */ +- u32 arb; /* PCI + 0x8C */ +- u8 reserved5[104]; /* PCI + 0x90 */ +- u32 car; /* PCI + 0xF8 */ +- u8 reserved6[4]; /* PCI + 0xFC */ +-}; +- +-#endif /* __ASSEMBLY__ */ +- +- +-#endif /* __SYSLIB_MPC52xx_PCI_H__ */ +diff --git a/arch/powerpc/platforms/52xx/pci.c b/arch/powerpc/platforms/52xx/pci.c +new file mode 100644 +index 0000000..14940af +--- /dev/null ++++ b/arch/powerpc/platforms/52xx/pci.c +@@ -0,0 +1,404 @@ ++/* ++ * PCI code for the Freescale MPC52xx embedded CPU. ++ * ++ * Copyright (C) 2004 Secret Lab Technologies Ltd. ++ * Grant Likely ++ * Copyright (C) 2004 Sylvain Munaut ++ * ++ * 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. ++ */ ++ ++#undef DEBUG ++ ++#include ++#include ++#include ++#include ++#include ++ ++ ++/* ======================================================================== */ ++/* PCI windows config */ ++/* ======================================================================== */ ++ ++#define MPC52xx_PCI_TARGET_IO 0xf0000000 ++#define MPC52xx_PCI_TARGET_MEM 0x00000000 ++ ++/* ======================================================================== */ ++/* Structures mapping & Defines for PCI Unit */ ++/* ======================================================================== */ ++ ++#define MPC52xx_PCI_GSCR_BM 0x40000000 ++#define MPC52xx_PCI_GSCR_PE 0x20000000 ++#define MPC52xx_PCI_GSCR_SE 0x10000000 ++#define MPC52xx_PCI_GSCR_XLB2PCI_MASK 0x07000000 ++#define MPC52xx_PCI_GSCR_XLB2PCI_SHIFT 24 ++#define MPC52xx_PCI_GSCR_IPG2PCI_MASK 0x00070000 ++#define MPC52xx_PCI_GSCR_IPG2PCI_SHIFT 16 ++#define MPC52xx_PCI_GSCR_BME 0x00004000 ++#define MPC52xx_PCI_GSCR_PEE 0x00002000 ++#define MPC52xx_PCI_GSCR_SEE 0x00001000 ++#define MPC52xx_PCI_GSCR_PR 0x00000001 ++ ++ ++#define MPC52xx_PCI_IWBTAR_TRANSLATION(proc_ad,pci_ad,size) \ ++ ( ( (proc_ad) & 0xff000000 ) | \ ++ ( (((size) - 1) >> 8) & 0x00ff0000 ) | \ ++ ( ((pci_ad) >> 16) & 0x0000ff00 ) ) ++ ++#define MPC52xx_PCI_IWCR_PACK(win0,win1,win2) (((win0) << 24) | \ ++ ((win1) << 16) | \ ++ ((win2) << 8)) ++ ++#define MPC52xx_PCI_IWCR_DISABLE 0x0 ++#define MPC52xx_PCI_IWCR_ENABLE 0x1 ++#define MPC52xx_PCI_IWCR_READ 0x0 ++#define MPC52xx_PCI_IWCR_READ_LINE 0x2 ++#define MPC52xx_PCI_IWCR_READ_MULTI 0x4 ++#define MPC52xx_PCI_IWCR_MEM 0x0 ++#define MPC52xx_PCI_IWCR_IO 0x8 ++ ++#define MPC52xx_PCI_TCR_P 0x01000000 ++#define MPC52xx_PCI_TCR_LD 0x00010000 ++ ++#define MPC52xx_PCI_TBATR_DISABLE 0x0 ++#define MPC52xx_PCI_TBATR_ENABLE 0x1 ++ ++struct mpc52xx_pci { ++ u32 idr; /* PCI + 0x00 */ ++ u32 scr; /* PCI + 0x04 */ ++ u32 ccrir; /* PCI + 0x08 */ ++ u32 cr1; /* PCI + 0x0C */ ++ u32 bar0; /* PCI + 0x10 */ ++ u32 bar1; /* PCI + 0x14 */ ++ u8 reserved1[16]; /* PCI + 0x18 */ ++ u32 ccpr; /* PCI + 0x28 */ ++ u32 sid; /* PCI + 0x2C */ ++ u32 erbar; /* PCI + 0x30 */ ++ u32 cpr; /* PCI + 0x34 */ ++ u8 reserved2[4]; /* PCI + 0x38 */ ++ u32 cr2; /* PCI + 0x3C */ ++ u8 reserved3[32]; /* PCI + 0x40 */ ++ u32 gscr; /* PCI + 0x60 */ ++ u32 tbatr0; /* PCI + 0x64 */ ++ u32 tbatr1; /* PCI + 0x68 */ ++ u32 tcr; /* PCI + 0x6C */ ++ u32 iw0btar; /* PCI + 0x70 */ ++ u32 iw1btar; /* PCI + 0x74 */ ++ u32 iw2btar; /* PCI + 0x78 */ ++ u8 reserved4[4]; /* PCI + 0x7C */ ++ u32 iwcr; /* PCI + 0x80 */ ++ u32 icr; /* PCI + 0x84 */ ++ u32 isr; /* PCI + 0x88 */ ++ u32 arb; /* PCI + 0x8C */ ++ u8 reserved5[104]; /* PCI + 0x90 */ ++ u32 car; /* PCI + 0xF8 */ ++ u8 reserved6[4]; /* PCI + 0xFC */ ++}; ++ ++static int ++mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, ++ int offset, int len, u32 *val) ++{ ++ struct pci_controller *hose = bus->sysdata; ++ u32 value; ++ ++ if (ppc_md.pci_exclude_device) ++ if (ppc_md.pci_exclude_device(bus->number, devfn)) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ out_be32(hose->cfg_addr, ++ (1 << 31) | ++ ((bus->number - hose->bus_offset) << 16) | ++ (devfn << 8) | ++ (offset & 0xfc)); ++ mb(); ++ ++#if defined(CONFIG_PPC_MPC5200_BUGFIX) ++ if (bus->number != hose->bus_offset) { ++ /* workaround for the bug 435 of the MPC5200 (L25R); ++ * Don't do 32 bits config access during type-1 cycles */ ++ switch (len) { ++ case 1: ++ value = in_8(((u8 __iomem *)hose->cfg_data) + ++ (offset & 3)); ++ break; ++ case 2: ++ value = in_le16(((u16 __iomem *)hose->cfg_data) + ++ ((offset>>1) & 1)); ++ break; ++ ++ default: ++ value = in_le16((u16 __iomem *)hose->cfg_data) | ++ (in_le16(((u16 __iomem *)hose->cfg_data) + 1) << 16); ++ break; ++ } ++ } ++ else ++#endif ++ { ++ value = in_le32(hose->cfg_data); ++ ++ if (len != 4) { ++ value >>= ((offset & 0x3) << 3); ++ value &= 0xffffffff >> (32 - (len << 3)); ++ } ++ } ++ ++ *val = value; ++ ++ out_be32(hose->cfg_addr, 0); ++ mb(); ++ ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++static int ++mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, ++ int offset, int len, u32 val) ++{ ++ struct pci_controller *hose = bus->sysdata; ++ u32 value, mask; ++ ++ if (ppc_md.pci_exclude_device) ++ if (ppc_md.pci_exclude_device(bus->number, devfn)) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ out_be32(hose->cfg_addr, ++ (1 << 31) | ++ ((bus->number - hose->bus_offset) << 16) | ++ (devfn << 8) | ++ (offset & 0xfc)); ++ mb(); ++ ++#if defined(CONFIG_PPC_MPC5200_BUGFIX) ++ if (bus->number != hose->bus_offset) { ++ /* workaround for the bug 435 of the MPC5200 (L25R); ++ * Don't do 32 bits config access during type-1 cycles */ ++ switch (len) { ++ case 1: ++ out_8(((u8 __iomem *)hose->cfg_data) + ++ (offset & 3), val); ++ break; ++ case 2: ++ out_le16(((u16 __iomem *)hose->cfg_data) + ++ ((offset>>1) & 1), val); ++ break; ++ ++ default: ++ out_le16((u16 __iomem *)hose->cfg_data, ++ (u16)val); ++ out_le16(((u16 __iomem *)hose->cfg_data) + 1, ++ (u16)(val>>16)); ++ break; ++ } ++ } ++ else ++#endif ++ { ++ if (len != 4) { ++ value = in_le32(hose->cfg_data); ++ ++ offset = (offset & 0x3) << 3; ++ mask = (0xffffffff >> (32 - (len << 3))); ++ mask <<= offset; ++ ++ value &= ~mask; ++ val = value | ((val << offset) & mask); ++ } ++ ++ out_le32(hose->cfg_data, val); ++ } ++ mb(); ++ ++ out_be32(hose->cfg_addr, 0); ++ mb(); ++ ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++static struct pci_ops mpc52xx_pci_ops = { ++ .read = mpc52xx_pci_read_config, ++ .write = mpc52xx_pci_write_config ++}; ++ ++ ++static void __init ++mpc52xx_pci_setup(struct pci_controller *hose, ++ struct mpc52xx_pci __iomem *pci_regs) ++{ ++ struct resource *res; ++ u32 tmp; ++ int iwcr0 = 0, iwcr1 = 0, iwcr2 = 0; ++ ++ pr_debug("mpc52xx_pci_setup(hose=%p, pci_regs=%p)\n", hose, pci_regs); ++ ++ /* pci_process_bridge_OF_ranges() found all our addresses for us; ++ * now store them in the right places */ ++ hose->cfg_addr = &pci_regs->car; ++ hose->cfg_data = hose->io_base_virt; ++ hose->io_base_virt = ioremap(hose->io_base_phys, ++ hose->io_resource.end + 1 - ++ hose->io_resource.start); ++ isa_io_base = (unsigned long) hose->io_base_virt; ++ ++ /* Control regs */ ++ tmp = in_be32(&pci_regs->scr); ++ tmp |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; ++ out_be32(&pci_regs->scr, tmp); ++ ++ /* Memory windows */ ++ res = &hose->mem_resources[0]; ++ if (res->flags) { ++ pr_debug("mem_resource[0] = {.start=%x, .end=%x, .flags=%lx}\n", ++ res->start, res->end, res->flags); ++ out_be32(&pci_regs->iw0btar, ++ MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start, ++ res->end - res->start + 1)); ++ iwcr0 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM; ++ if (res->flags & IORESOURCE_PREFETCH) ++ iwcr0 |= MPC52xx_PCI_IWCR_READ_MULTI; ++ else ++ iwcr0 |= MPC52xx_PCI_IWCR_READ; ++ } ++ ++ res = &hose->mem_resources[1]; ++ if (res->flags) { ++ pr_debug("mem_resource[1] = {.start=%x, .end=%x, .flags=%lx}\n", ++ res->start, res->end, res->flags); ++ out_be32(&pci_regs->iw1btar, ++ MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start, ++ res->end - res->start + 1)); ++ iwcr1 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM; ++ if (res->flags & IORESOURCE_PREFETCH) ++ iwcr1 |= MPC52xx_PCI_IWCR_READ_MULTI; ++ else ++ iwcr1 |= MPC52xx_PCI_IWCR_READ; ++ } ++ ++ /* IO resources */ ++ res = &hose->io_resource; ++ if (!res) { ++ printk(KERN_ERR "%s: Didn't find IO resources\n", __FILE__); ++ return; ++ } ++ pr_debug(".io_resource={.start=%x,.end=%x,.flags=%lx} " ++ ".io_base_phys=%lx\n", ++ res->start, res->end, res->flags, hose->io_base_phys); ++ out_be32(&pci_regs->iw2btar, ++ MPC52xx_PCI_IWBTAR_TRANSLATION(hose->io_base_phys, ++ res->start, ++ res->end - res->start + 1)); ++ iwcr2 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_IO; ++ ++ /* Set all the IWCR fields at once; they're in the same reg */ ++ out_be32(&pci_regs->iwcr, MPC52xx_PCI_IWCR_PACK(iwcr0, iwcr1, iwcr2)); ++ ++ out_be32(&pci_regs->tbatr0, ++ MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_IO ); ++ out_be32(&pci_regs->tbatr1, ++ MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_MEM ); ++ ++ out_be32(&pci_regs->tcr, MPC52xx_PCI_TCR_LD); ++ ++#if 0 ++ /* Reset the exteral bus ( internal PCI controller is NOT resetted ) */ ++ /* Not necessary and can be a bad thing if for example the bootloader ++ is displaying a splash screen or ... Just left here for ++ documentation purpose if anyone need it */ ++ tmp = in_be32(&pci_regs->gscr); ++ out_be32(&pci_regs->gscr, tmp | MPC52xx_PCI_GSCR_PR); ++ udelay(50); ++ out_be32(&pci_regs->gscr, tmp & ~MPC52xx_PCI_GSCR_PR); ++#endif ++} ++ ++static void ++mpc52xx_pci_fixup_resources(struct pci_dev *dev) ++{ ++ int i; ++ ++ pr_debug("mpc52xx_pci_fixup_resources() %.4x:%.4x\n", ++ dev->vendor, dev->device); ++ ++ /* We don't rely on boot loader for PCI and resets all ++ devices */ ++ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { ++ struct resource *res = &dev->resource[i]; ++ if (res->end > res->start) { /* Only valid resources */ ++ res->end -= res->start; ++ res->start = 0; ++ res->flags |= IORESOURCE_UNSET; ++ } ++ } ++ ++ /* The PCI Host bridge of MPC52xx has a prefetch memory resource ++ fixed to 1Gb. Doesn't fit in the resource system so we remove it */ ++ if ( (dev->vendor == PCI_VENDOR_ID_MOTOROLA) && ++ ( dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200 ++ || dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200B) ) { ++ struct resource *res = &dev->resource[1]; ++ res->start = res->end = res->flags = 0; ++ } ++} ++ ++int __init ++mpc52xx_add_bridge(struct device_node *node) ++{ ++ int len; ++ struct mpc52xx_pci __iomem *pci_regs; ++ struct pci_controller *hose; ++ const int *bus_range; ++ struct resource rsrc; ++ ++ pr_debug("Adding MPC52xx PCI host bridge %s\n", node->full_name); ++ ++ pci_assign_all_buses = 1; ++ ++ if (of_address_to_resource(node, 0, &rsrc) != 0) { ++ printk(KERN_ERR "Can't get %s resources\n", node->full_name); ++ return -EINVAL; ++ } ++ ++ bus_range = get_property(node, "bus-range", &len); ++ if (bus_range == NULL || len < 2 * sizeof(int)) { ++ printk(KERN_WARNING "Can't get %s bus-range, assume bus 0\n", ++ node->full_name); ++ bus_range = NULL; ++ } ++ ++ /* There are some PCI quirks on the 52xx, register the hook to ++ * fix them. */ ++ ppc_md.pcibios_fixup_resources = mpc52xx_pci_fixup_resources; ++ ++ /* Alloc and initialize the pci controller. Values in the device ++ * tree are needed to configure the 52xx PCI controller. Rather ++ * than parse the tree here, let pci_process_bridge_OF_ranges() ++ * do it for us and extract the values after the fact */ ++ hose = pcibios_alloc_controller(); ++ if (!hose) ++ return -ENOMEM; ++ ++ hose->arch_data = node; ++ hose->set_cfg_type = 1; ++ ++ hose->first_busno = bus_range ? bus_range[0] : 0; ++ hose->last_busno = bus_range ? bus_range[1] : 0xff; ++ ++ hose->bus_offset = 0; ++ hose->ops = &mpc52xx_pci_ops; ++ ++ pci_regs = ioremap(rsrc.start, rsrc.end - rsrc.start + 1); ++ if (!pci_regs) ++ return -ENOMEM; ++ ++ pci_process_bridge_OF_ranges(hose, node, 0); ++ ++ /* Finish setting up PCI using values obtained by ++ * pci_proces_bridge_OF_ranges */ ++ mpc52xx_pci_setup(hose, pci_regs); ++ ++ return 0; ++} +-- +1.4.4.2 + diff --git a/debian/patches/features/powerpc/efika/0027-POWERPC-Change-name-of-mpc52xx-pci-support-file-in-Makefile.txt b/debian/patches/features/powerpc/efika/0027-POWERPC-Change-name-of-mpc52xx-pci-support-file-in-Makefile.txt new file mode 100644 index 000000000..80a769b9b --- /dev/null +++ b/debian/patches/features/powerpc/efika/0027-POWERPC-Change-name-of-mpc52xx-pci-support-file-in-Makefile.txt @@ -0,0 +1,28 @@ +From 5145742e15b45e96c623f571dee421306dc95a3e Mon Sep 17 00:00:00 2001 +From: Grant Likely +Date: Mon, 11 Dec 2006 22:45:39 -0700 +Subject: [PATCH] [POWERPC] Change name of mpc52xx pci support file in Makefile + +Oops, missed a bit in the previous patch + +Signed-off-by: Grant Likely +--- + arch/powerpc/platforms/52xx/Makefile | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/arch/powerpc/platforms/52xx/Makefile b/arch/powerpc/platforms/52xx/Makefile +index d85ea04..a7c646a 100644 +--- a/arch/powerpc/platforms/52xx/Makefile ++++ b/arch/powerpc/platforms/52xx/Makefile +@@ -3,7 +3,7 @@ + # + ifeq ($(CONFIG_PPC_MERGE),y) + obj-y += mpc52xx_pic.o mpc52xx_common.o +-obj-$(CONFIG_PCI) += mpc52xx_pci.o ++obj-$(CONFIG_PCI) += pci.o + obj-$(CONFIG_PPC_BESTCOMM) += bestcomm.o + obj-$(CONFIG_FEC_MPC52xx) += sdma_fec_rx_task.o sdma_fec_tx_task.o fec.o + endif +-- +1.4.4.2 + diff --git a/debian/patches/features/powerpc/efika/0028-POWERPC-Change-link-order-so-mpc52xx-fec-always-shows-up-as-eth0.txt b/debian/patches/features/powerpc/efika/0028-POWERPC-Change-link-order-so-mpc52xx-fec-always-shows-up-as-eth0.txt new file mode 100644 index 000000000..0761bea35 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0028-POWERPC-Change-link-order-so-mpc52xx-fec-always-shows-up-as-eth0.txt @@ -0,0 +1,47 @@ +From 2086d309f8b8de0b41119596d43f2a7bfe028a89 Mon Sep 17 00:00:00 2001 +From: Grant Likely +Date: Mon, 11 Dec 2006 22:46:59 -0700 +Subject: [PATCH] [POWERPC] Change link order so mpc52xx-fec always shows up as eth0 + +Signed-off-by: Grant Likely +--- + drivers/net/Makefile | 2 +- + drivers/net/fec_mpc52xx/fec.c | 2 ++ + 2 files changed, 3 insertions(+), 1 deletions(-) + +diff --git a/drivers/net/Makefile b/drivers/net/Makefile +index e6f903d..95f0963 100644 +--- a/drivers/net/Makefile ++++ b/drivers/net/Makefile +@@ -24,6 +24,7 @@ ucc_geth_driver-objs := ucc_geth.o ucc_geth_phy.o + obj-$(CONFIG_PLIP) += plip.o + + obj-$(CONFIG_ROADRUNNER) += rrunner.o ++obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx/ + + obj-$(CONFIG_HAPPYMEAL) += sunhme.o + obj-$(CONFIG_SUNLANCE) += sunlance.o +@@ -196,7 +197,6 @@ obj-$(CONFIG_SMC91X) += smc91x.o + obj-$(CONFIG_SMC911X) += smc911x.o + obj-$(CONFIG_DM9000) += dm9000.o + obj-$(CONFIG_FEC_8XX) += fec_8xx/ +-obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx/ + + obj-$(CONFIG_MACB) += macb.o + +diff --git a/drivers/net/fec_mpc52xx/fec.c b/drivers/net/fec_mpc52xx/fec.c +index 894da79..30cef2b 100644 +--- a/drivers/net/fec_mpc52xx/fec.c ++++ b/drivers/net/fec_mpc52xx/fec.c +@@ -731,6 +731,8 @@ mpc52xx_fec_probe(struct device *dev) + fec_mii_init(ndev); + + /* We're done ! */ ++ printk(KERN_INFO "%s: mpc52xx-fec at %#lx,", ++ ndev->name, (long)mem->start); + #if defined(CONFIG_PPC_MERGE) + dev_set_drvdata(&op->dev, ndev); + #else +-- +1.4.4.2 + diff --git a/debian/patches/features/powerpc/efika/0029-POWERPC-Fixup-pr_print-format-for-mpc52xx-pci-support.txt b/debian/patches/features/powerpc/efika/0029-POWERPC-Fixup-pr_print-format-for-mpc52xx-pci-support.txt new file mode 100644 index 000000000..3a1793924 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0029-POWERPC-Fixup-pr_print-format-for-mpc52xx-pci-support.txt @@ -0,0 +1,28 @@ +From 08bb999d4f8b866a570775db5788cd84edafd3f5 Mon Sep 17 00:00:00 2001 +From: Grant Likely +Date: Mon, 11 Dec 2006 23:00:24 -0700 +Subject: [PATCH] [POWERPC] Fixup pr_print format for mpc52xx pci support + +Signed-off-by: Grant Likely +--- + arch/powerpc/platforms/52xx/pci.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/powerpc/platforms/52xx/pci.c b/arch/powerpc/platforms/52xx/pci.c +index 14940af..b732fdc 100644 +--- a/arch/powerpc/platforms/52xx/pci.c ++++ b/arch/powerpc/platforms/52xx/pci.c +@@ -285,8 +285,8 @@ mpc52xx_pci_setup(struct pci_controller *hose, + return; + } + pr_debug(".io_resource={.start=%x,.end=%x,.flags=%lx} " +- ".io_base_phys=%lx\n", +- res->start, res->end, res->flags, hose->io_base_phys); ++ ".io_base_phys=0x%p\n", ++ res->start, res->end, res->flags, (void*)hose->io_base_phys); + out_be32(&pci_regs->iw2btar, + MPC52xx_PCI_IWBTAR_TRANSLATION(hose->io_base_phys, + res->start, +-- +1.4.4.2 + diff --git a/debian/patches/features/powerpc/efika/0030-POWERPC-Add-mpc52xx-lite5200-PCI-support.txt b/debian/patches/features/powerpc/efika/0030-POWERPC-Add-mpc52xx-lite5200-PCI-support.txt new file mode 100644 index 000000000..dae76e0d7 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0030-POWERPC-Add-mpc52xx-lite5200-PCI-support.txt @@ -0,0 +1,871 @@ +From 56aad819c662c854466a8c454c948e79dd2f0777 Mon Sep 17 00:00:00 2001 +From: Grant Likely +Date: Mon, 11 Dec 2006 23:23:40 -0700 +Subject: [PATCH] [POWERPC] Add mpc52xx/lite5200 PCI support + +Signed-off-by: Grant Likely +--- + arch/powerpc/platforms/52xx/Makefile | 2 +- + arch/powerpc/platforms/52xx/lite5200.c | 3 - + arch/powerpc/platforms/52xx/mpc52xx_pci.c | 412 +++++++++++++++++++++++++++++ + arch/powerpc/platforms/52xx/pci.c | 404 ---------------------------- + 4 files changed, 413 insertions(+), 408 deletions(-) + +diff --git a/arch/powerpc/platforms/52xx/Makefile b/arch/powerpc/platforms/52xx/Makefile +index a7c646a..d85ea04 100644 +--- a/arch/powerpc/platforms/52xx/Makefile ++++ b/arch/powerpc/platforms/52xx/Makefile +@@ -3,7 +3,7 @@ + # + ifeq ($(CONFIG_PPC_MERGE),y) + obj-y += mpc52xx_pic.o mpc52xx_common.o +-obj-$(CONFIG_PCI) += pci.o ++obj-$(CONFIG_PCI) += mpc52xx_pci.o + obj-$(CONFIG_PPC_BESTCOMM) += bestcomm.o + obj-$(CONFIG_FEC_MPC52xx) += sdma_fec_rx_task.o sdma_fec_tx_task.o fec.o + endif +diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c +index f1bbe24..cdb16bf 100644 +--- a/arch/powerpc/platforms/52xx/lite5200.c ++++ b/arch/powerpc/platforms/52xx/lite5200.c +@@ -111,9 +111,6 @@ static void __init lite52xx_setup_arch(void) + np = of_find_node_by_type(np, "pci"); + if (np) + mpc52xx_add_bridge(np); +- +- //ppc_md.pci_swizzle = common_swizzle; +- //ppc_md.pci_exclude_device = mpc52xx_exclude_device; + #endif + + #ifdef CONFIG_BLK_DEV_INITRD +diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c +new file mode 100644 +index 0000000..faf161b +--- /dev/null ++++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c +@@ -0,0 +1,412 @@ ++/* ++ * PCI code for the Freescale MPC52xx embedded CPU. ++ * ++ * Copyright (C) 2006 Secret Lab Technologies Ltd. ++ * Grant Likely ++ * Copyright (C) 2004 Sylvain Munaut ++ * ++ * 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. ++ */ ++ ++#undef DEBUG ++ ++#include ++#include ++#include ++#include ++#include ++ ++ ++/* ======================================================================== */ ++/* PCI windows config */ ++/* ======================================================================== */ ++ ++#define MPC52xx_PCI_TARGET_IO 0xf0000000 ++#define MPC52xx_PCI_TARGET_MEM 0x00000000 ++ ++ ++/* ======================================================================== */ ++/* Structures mapping & Defines for PCI Unit */ ++/* ======================================================================== */ ++ ++#define MPC52xx_PCI_GSCR_BM 0x40000000 ++#define MPC52xx_PCI_GSCR_PE 0x20000000 ++#define MPC52xx_PCI_GSCR_SE 0x10000000 ++#define MPC52xx_PCI_GSCR_XLB2PCI_MASK 0x07000000 ++#define MPC52xx_PCI_GSCR_XLB2PCI_SHIFT 24 ++#define MPC52xx_PCI_GSCR_IPG2PCI_MASK 0x00070000 ++#define MPC52xx_PCI_GSCR_IPG2PCI_SHIFT 16 ++#define MPC52xx_PCI_GSCR_BME 0x00004000 ++#define MPC52xx_PCI_GSCR_PEE 0x00002000 ++#define MPC52xx_PCI_GSCR_SEE 0x00001000 ++#define MPC52xx_PCI_GSCR_PR 0x00000001 ++ ++ ++#define MPC52xx_PCI_IWBTAR_TRANSLATION(proc_ad,pci_ad,size) \ ++ ( ( (proc_ad) & 0xff000000 ) | \ ++ ( (((size) - 1) >> 8) & 0x00ff0000 ) | \ ++ ( ((pci_ad) >> 16) & 0x0000ff00 ) ) ++ ++#define MPC52xx_PCI_IWCR_PACK(win0,win1,win2) (((win0) << 24) | \ ++ ((win1) << 16) | \ ++ ((win2) << 8)) ++ ++#define MPC52xx_PCI_IWCR_DISABLE 0x0 ++#define MPC52xx_PCI_IWCR_ENABLE 0x1 ++#define MPC52xx_PCI_IWCR_READ 0x0 ++#define MPC52xx_PCI_IWCR_READ_LINE 0x2 ++#define MPC52xx_PCI_IWCR_READ_MULTI 0x4 ++#define MPC52xx_PCI_IWCR_MEM 0x0 ++#define MPC52xx_PCI_IWCR_IO 0x8 ++ ++#define MPC52xx_PCI_TCR_P 0x01000000 ++#define MPC52xx_PCI_TCR_LD 0x00010000 ++ ++#define MPC52xx_PCI_TBATR_DISABLE 0x0 ++#define MPC52xx_PCI_TBATR_ENABLE 0x1 ++ ++struct mpc52xx_pci { ++ u32 idr; /* PCI + 0x00 */ ++ u32 scr; /* PCI + 0x04 */ ++ u32 ccrir; /* PCI + 0x08 */ ++ u32 cr1; /* PCI + 0x0C */ ++ u32 bar0; /* PCI + 0x10 */ ++ u32 bar1; /* PCI + 0x14 */ ++ u8 reserved1[16]; /* PCI + 0x18 */ ++ u32 ccpr; /* PCI + 0x28 */ ++ u32 sid; /* PCI + 0x2C */ ++ u32 erbar; /* PCI + 0x30 */ ++ u32 cpr; /* PCI + 0x34 */ ++ u8 reserved2[4]; /* PCI + 0x38 */ ++ u32 cr2; /* PCI + 0x3C */ ++ u8 reserved3[32]; /* PCI + 0x40 */ ++ u32 gscr; /* PCI + 0x60 */ ++ u32 tbatr0; /* PCI + 0x64 */ ++ u32 tbatr1; /* PCI + 0x68 */ ++ u32 tcr; /* PCI + 0x6C */ ++ u32 iw0btar; /* PCI + 0x70 */ ++ u32 iw1btar; /* PCI + 0x74 */ ++ u32 iw2btar; /* PCI + 0x78 */ ++ u8 reserved4[4]; /* PCI + 0x7C */ ++ u32 iwcr; /* PCI + 0x80 */ ++ u32 icr; /* PCI + 0x84 */ ++ u32 isr; /* PCI + 0x88 */ ++ u32 arb; /* PCI + 0x8C */ ++ u8 reserved5[104]; /* PCI + 0x90 */ ++ u32 car; /* PCI + 0xF8 */ ++ u8 reserved6[4]; /* PCI + 0xFC */ ++}; ++ ++ ++/* ======================================================================== */ ++/* PCI configuration acess */ ++/* ======================================================================== */ ++ ++static int ++mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, ++ int offset, int len, u32 *val) ++{ ++ struct pci_controller *hose = bus->sysdata; ++ u32 value; ++ ++ if (ppc_md.pci_exclude_device) ++ if (ppc_md.pci_exclude_device(bus->number, devfn)) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ out_be32(hose->cfg_addr, ++ (1 << 31) | ++ ((bus->number - hose->bus_offset) << 16) | ++ (devfn << 8) | ++ (offset & 0xfc)); ++ mb(); ++ ++#if defined(CONFIG_PPC_MPC5200_BUGFIX) ++ if (bus->number != hose->bus_offset) { ++ /* workaround for the bug 435 of the MPC5200 (L25R); ++ * Don't do 32 bits config access during type-1 cycles */ ++ switch (len) { ++ case 1: ++ value = in_8(((u8 __iomem *)hose->cfg_data) + ++ (offset & 3)); ++ break; ++ case 2: ++ value = in_le16(((u16 __iomem *)hose->cfg_data) + ++ ((offset>>1) & 1)); ++ break; ++ ++ default: ++ value = in_le16((u16 __iomem *)hose->cfg_data) | ++ (in_le16(((u16 __iomem *)hose->cfg_data) + 1) << 16); ++ break; ++ } ++ } ++ else ++#endif ++ { ++ value = in_le32(hose->cfg_data); ++ ++ if (len != 4) { ++ value >>= ((offset & 0x3) << 3); ++ value &= 0xffffffff >> (32 - (len << 3)); ++ } ++ } ++ ++ *val = value; ++ ++ out_be32(hose->cfg_addr, 0); ++ mb(); ++ ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++static int ++mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, ++ int offset, int len, u32 val) ++{ ++ struct pci_controller *hose = bus->sysdata; ++ u32 value, mask; ++ ++ if (ppc_md.pci_exclude_device) ++ if (ppc_md.pci_exclude_device(bus->number, devfn)) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ out_be32(hose->cfg_addr, ++ (1 << 31) | ++ ((bus->number - hose->bus_offset) << 16) | ++ (devfn << 8) | ++ (offset & 0xfc)); ++ mb(); ++ ++#if defined(CONFIG_PPC_MPC5200_BUGFIX) ++ if (bus->number != hose->bus_offset) { ++ /* workaround for the bug 435 of the MPC5200 (L25R); ++ * Don't do 32 bits config access during type-1 cycles */ ++ switch (len) { ++ case 1: ++ out_8(((u8 __iomem *)hose->cfg_data) + ++ (offset & 3), val); ++ break; ++ case 2: ++ out_le16(((u16 __iomem *)hose->cfg_data) + ++ ((offset>>1) & 1), val); ++ break; ++ ++ default: ++ out_le16((u16 __iomem *)hose->cfg_data, ++ (u16)val); ++ out_le16(((u16 __iomem *)hose->cfg_data) + 1, ++ (u16)(val>>16)); ++ break; ++ } ++ } ++ else ++#endif ++ { ++ if (len != 4) { ++ value = in_le32(hose->cfg_data); ++ ++ offset = (offset & 0x3) << 3; ++ mask = (0xffffffff >> (32 - (len << 3))); ++ mask <<= offset; ++ ++ value &= ~mask; ++ val = value | ((val << offset) & mask); ++ } ++ ++ out_le32(hose->cfg_data, val); ++ } ++ mb(); ++ ++ out_be32(hose->cfg_addr, 0); ++ mb(); ++ ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++static struct pci_ops mpc52xx_pci_ops = { ++ .read = mpc52xx_pci_read_config, ++ .write = mpc52xx_pci_write_config ++}; ++ ++ ++/* ======================================================================== */ ++/* PCI setup */ ++/* ======================================================================== */ ++ ++static void __init ++mpc52xx_pci_setup(struct pci_controller *hose, ++ struct mpc52xx_pci __iomem *pci_regs) ++{ ++ struct resource *res; ++ u32 tmp; ++ int iwcr0 = 0, iwcr1 = 0, iwcr2 = 0; ++ ++ pr_debug("mpc52xx_pci_setup(hose=%p, pci_regs=%p)\n", hose, pci_regs); ++ ++ /* pci_process_bridge_OF_ranges() found all our addresses for us; ++ * now store them in the right places */ ++ hose->cfg_addr = &pci_regs->car; ++ hose->cfg_data = hose->io_base_virt; ++ ++ /* Control regs */ ++ tmp = in_be32(&pci_regs->scr); ++ tmp |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; ++ out_be32(&pci_regs->scr, tmp); ++ ++ /* Memory windows */ ++ res = &hose->mem_resources[0]; ++ if (res->flags) { ++ pr_debug("mem_resource[0] = {.start=%x, .end=%x, .flags=%lx}\n", ++ res->start, res->end, res->flags); ++ out_be32(&pci_regs->iw0btar, ++ MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start, ++ res->end - res->start + 1)); ++ iwcr0 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM; ++ if (res->flags & IORESOURCE_PREFETCH) ++ iwcr0 |= MPC52xx_PCI_IWCR_READ_MULTI; ++ else ++ iwcr0 |= MPC52xx_PCI_IWCR_READ; ++ } ++ ++ res = &hose->mem_resources[1]; ++ if (res->flags) { ++ pr_debug("mem_resource[1] = {.start=%x, .end=%x, .flags=%lx}\n", ++ res->start, res->end, res->flags); ++ out_be32(&pci_regs->iw1btar, ++ MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start, ++ res->end - res->start + 1)); ++ iwcr1 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM; ++ if (res->flags & IORESOURCE_PREFETCH) ++ iwcr1 |= MPC52xx_PCI_IWCR_READ_MULTI; ++ else ++ iwcr1 |= MPC52xx_PCI_IWCR_READ; ++ } ++ ++ /* IO resources */ ++ res = &hose->io_resource; ++ if (!res) { ++ printk(KERN_ERR "%s: Didn't find IO resources\n", __FILE__); ++ return; ++ } ++ pr_debug(".io_resource={.start=%x,.end=%x,.flags=%lx} " ++ ".io_base_phys=0x%p\n", ++ res->start, res->end, res->flags, (void*)hose->io_base_phys); ++ out_be32(&pci_regs->iw2btar, ++ MPC52xx_PCI_IWBTAR_TRANSLATION(hose->io_base_phys, ++ res->start, ++ res->end - res->start + 1)); ++ iwcr2 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_IO; ++ ++ /* Set all the IWCR fields at once; they're in the same reg */ ++ out_be32(&pci_regs->iwcr, MPC52xx_PCI_IWCR_PACK(iwcr0, iwcr1, iwcr2)); ++ ++ out_be32(&pci_regs->tbatr0, ++ MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_IO ); ++ out_be32(&pci_regs->tbatr1, ++ MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_MEM ); ++ ++ out_be32(&pci_regs->tcr, MPC52xx_PCI_TCR_LD); ++ ++ tmp = in_be32(&pci_regs->gscr); ++#if 0 ++ /* Reset the exteral bus ( internal PCI controller is NOT resetted ) */ ++ /* Not necessary and can be a bad thing if for example the bootloader ++ is displaying a splash screen or ... Just left here for ++ documentation purpose if anyone need it */ ++ out_be32(&pci_regs->gscr, tmp | MPC52xx_PCI_GSCR_PR); ++ udelay(50); ++#endif ++ ++ /* Make sure the PCI bridge is out of reset */ ++ out_be32(&pci_regs->gscr, tmp & ~MPC52xx_PCI_GSCR_PR); ++} ++ ++static void ++mpc52xx_pci_fixup_resources(struct pci_dev *dev) ++{ ++ int i; ++ ++ pr_debug("mpc52xx_pci_fixup_resources() %.4x:%.4x\n", ++ dev->vendor, dev->device); ++ ++ /* We don't rely on boot loader for PCI and resets all ++ devices */ ++ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { ++ struct resource *res = &dev->resource[i]; ++ if (res->end > res->start) { /* Only valid resources */ ++ res->end -= res->start; ++ res->start = 0; ++ res->flags |= IORESOURCE_UNSET; ++ } ++ } ++ ++ /* The PCI Host bridge of MPC52xx has a prefetch memory resource ++ fixed to 1Gb. Doesn't fit in the resource system so we remove it */ ++ if ( (dev->vendor == PCI_VENDOR_ID_MOTOROLA) && ++ ( dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200 ++ || dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200B) ) { ++ struct resource *res = &dev->resource[1]; ++ res->start = res->end = res->flags = 0; ++ } ++} ++ ++int __init ++mpc52xx_add_bridge(struct device_node *node) ++{ ++ int len; ++ struct mpc52xx_pci __iomem *pci_regs; ++ struct pci_controller *hose; ++ const int *bus_range; ++ struct resource rsrc; ++ ++ pr_debug("Adding MPC52xx PCI host bridge %s\n", node->full_name); ++ ++ pci_assign_all_buses = 1; ++ ++ if (of_address_to_resource(node, 0, &rsrc) != 0) { ++ printk(KERN_ERR "Can't get %s resources\n", node->full_name); ++ return -EINVAL; ++ } ++ ++ bus_range = get_property(node, "bus-range", &len); ++ if (bus_range == NULL || len < 2 * sizeof(int)) { ++ printk(KERN_WARNING "Can't get %s bus-range, assume bus 0\n", ++ node->full_name); ++ bus_range = NULL; ++ } ++ ++ /* There are some PCI quirks on the 52xx, register the hook to ++ * fix them. */ ++ ppc_md.pcibios_fixup_resources = mpc52xx_pci_fixup_resources; ++ ++ /* Alloc and initialize the pci controller. Values in the device ++ * tree are needed to configure the 52xx PCI controller. Rather ++ * than parse the tree here, let pci_process_bridge_OF_ranges() ++ * do it for us and extract the values after the fact */ ++ hose = pcibios_alloc_controller(); ++ if (!hose) ++ return -ENOMEM; ++ ++ hose->arch_data = node; ++ hose->set_cfg_type = 1; ++ ++ hose->first_busno = bus_range ? bus_range[0] : 0; ++ hose->last_busno = bus_range ? bus_range[1] : 0xff; ++ ++ hose->bus_offset = 0; ++ hose->ops = &mpc52xx_pci_ops; ++ ++ pci_regs = ioremap(rsrc.start, rsrc.end - rsrc.start + 1); ++ if (!pci_regs) ++ return -ENOMEM; ++ ++ pci_process_bridge_OF_ranges(hose, node, 1); ++ ++ /* Finish setting up PCI using values obtained by ++ * pci_proces_bridge_OF_ranges */ ++ mpc52xx_pci_setup(hose, pci_regs); ++ ++ return 0; ++} +diff --git a/arch/powerpc/platforms/52xx/pci.c b/arch/powerpc/platforms/52xx/pci.c +deleted file mode 100644 +index b732fdc..0000000 +--- a/arch/powerpc/platforms/52xx/pci.c ++++ /dev/null +@@ -1,404 +0,0 @@ +-/* +- * PCI code for the Freescale MPC52xx embedded CPU. +- * +- * Copyright (C) 2004 Secret Lab Technologies Ltd. +- * Grant Likely +- * Copyright (C) 2004 Sylvain Munaut +- * +- * 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. +- */ +- +-#undef DEBUG +- +-#include +-#include +-#include +-#include +-#include +- +- +-/* ======================================================================== */ +-/* PCI windows config */ +-/* ======================================================================== */ +- +-#define MPC52xx_PCI_TARGET_IO 0xf0000000 +-#define MPC52xx_PCI_TARGET_MEM 0x00000000 +- +-/* ======================================================================== */ +-/* Structures mapping & Defines for PCI Unit */ +-/* ======================================================================== */ +- +-#define MPC52xx_PCI_GSCR_BM 0x40000000 +-#define MPC52xx_PCI_GSCR_PE 0x20000000 +-#define MPC52xx_PCI_GSCR_SE 0x10000000 +-#define MPC52xx_PCI_GSCR_XLB2PCI_MASK 0x07000000 +-#define MPC52xx_PCI_GSCR_XLB2PCI_SHIFT 24 +-#define MPC52xx_PCI_GSCR_IPG2PCI_MASK 0x00070000 +-#define MPC52xx_PCI_GSCR_IPG2PCI_SHIFT 16 +-#define MPC52xx_PCI_GSCR_BME 0x00004000 +-#define MPC52xx_PCI_GSCR_PEE 0x00002000 +-#define MPC52xx_PCI_GSCR_SEE 0x00001000 +-#define MPC52xx_PCI_GSCR_PR 0x00000001 +- +- +-#define MPC52xx_PCI_IWBTAR_TRANSLATION(proc_ad,pci_ad,size) \ +- ( ( (proc_ad) & 0xff000000 ) | \ +- ( (((size) - 1) >> 8) & 0x00ff0000 ) | \ +- ( ((pci_ad) >> 16) & 0x0000ff00 ) ) +- +-#define MPC52xx_PCI_IWCR_PACK(win0,win1,win2) (((win0) << 24) | \ +- ((win1) << 16) | \ +- ((win2) << 8)) +- +-#define MPC52xx_PCI_IWCR_DISABLE 0x0 +-#define MPC52xx_PCI_IWCR_ENABLE 0x1 +-#define MPC52xx_PCI_IWCR_READ 0x0 +-#define MPC52xx_PCI_IWCR_READ_LINE 0x2 +-#define MPC52xx_PCI_IWCR_READ_MULTI 0x4 +-#define MPC52xx_PCI_IWCR_MEM 0x0 +-#define MPC52xx_PCI_IWCR_IO 0x8 +- +-#define MPC52xx_PCI_TCR_P 0x01000000 +-#define MPC52xx_PCI_TCR_LD 0x00010000 +- +-#define MPC52xx_PCI_TBATR_DISABLE 0x0 +-#define MPC52xx_PCI_TBATR_ENABLE 0x1 +- +-struct mpc52xx_pci { +- u32 idr; /* PCI + 0x00 */ +- u32 scr; /* PCI + 0x04 */ +- u32 ccrir; /* PCI + 0x08 */ +- u32 cr1; /* PCI + 0x0C */ +- u32 bar0; /* PCI + 0x10 */ +- u32 bar1; /* PCI + 0x14 */ +- u8 reserved1[16]; /* PCI + 0x18 */ +- u32 ccpr; /* PCI + 0x28 */ +- u32 sid; /* PCI + 0x2C */ +- u32 erbar; /* PCI + 0x30 */ +- u32 cpr; /* PCI + 0x34 */ +- u8 reserved2[4]; /* PCI + 0x38 */ +- u32 cr2; /* PCI + 0x3C */ +- u8 reserved3[32]; /* PCI + 0x40 */ +- u32 gscr; /* PCI + 0x60 */ +- u32 tbatr0; /* PCI + 0x64 */ +- u32 tbatr1; /* PCI + 0x68 */ +- u32 tcr; /* PCI + 0x6C */ +- u32 iw0btar; /* PCI + 0x70 */ +- u32 iw1btar; /* PCI + 0x74 */ +- u32 iw2btar; /* PCI + 0x78 */ +- u8 reserved4[4]; /* PCI + 0x7C */ +- u32 iwcr; /* PCI + 0x80 */ +- u32 icr; /* PCI + 0x84 */ +- u32 isr; /* PCI + 0x88 */ +- u32 arb; /* PCI + 0x8C */ +- u8 reserved5[104]; /* PCI + 0x90 */ +- u32 car; /* PCI + 0xF8 */ +- u8 reserved6[4]; /* PCI + 0xFC */ +-}; +- +-static int +-mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, +- int offset, int len, u32 *val) +-{ +- struct pci_controller *hose = bus->sysdata; +- u32 value; +- +- if (ppc_md.pci_exclude_device) +- if (ppc_md.pci_exclude_device(bus->number, devfn)) +- return PCIBIOS_DEVICE_NOT_FOUND; +- +- out_be32(hose->cfg_addr, +- (1 << 31) | +- ((bus->number - hose->bus_offset) << 16) | +- (devfn << 8) | +- (offset & 0xfc)); +- mb(); +- +-#if defined(CONFIG_PPC_MPC5200_BUGFIX) +- if (bus->number != hose->bus_offset) { +- /* workaround for the bug 435 of the MPC5200 (L25R); +- * Don't do 32 bits config access during type-1 cycles */ +- switch (len) { +- case 1: +- value = in_8(((u8 __iomem *)hose->cfg_data) + +- (offset & 3)); +- break; +- case 2: +- value = in_le16(((u16 __iomem *)hose->cfg_data) + +- ((offset>>1) & 1)); +- break; +- +- default: +- value = in_le16((u16 __iomem *)hose->cfg_data) | +- (in_le16(((u16 __iomem *)hose->cfg_data) + 1) << 16); +- break; +- } +- } +- else +-#endif +- { +- value = in_le32(hose->cfg_data); +- +- if (len != 4) { +- value >>= ((offset & 0x3) << 3); +- value &= 0xffffffff >> (32 - (len << 3)); +- } +- } +- +- *val = value; +- +- out_be32(hose->cfg_addr, 0); +- mb(); +- +- return PCIBIOS_SUCCESSFUL; +-} +- +-static int +-mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, +- int offset, int len, u32 val) +-{ +- struct pci_controller *hose = bus->sysdata; +- u32 value, mask; +- +- if (ppc_md.pci_exclude_device) +- if (ppc_md.pci_exclude_device(bus->number, devfn)) +- return PCIBIOS_DEVICE_NOT_FOUND; +- +- out_be32(hose->cfg_addr, +- (1 << 31) | +- ((bus->number - hose->bus_offset) << 16) | +- (devfn << 8) | +- (offset & 0xfc)); +- mb(); +- +-#if defined(CONFIG_PPC_MPC5200_BUGFIX) +- if (bus->number != hose->bus_offset) { +- /* workaround for the bug 435 of the MPC5200 (L25R); +- * Don't do 32 bits config access during type-1 cycles */ +- switch (len) { +- case 1: +- out_8(((u8 __iomem *)hose->cfg_data) + +- (offset & 3), val); +- break; +- case 2: +- out_le16(((u16 __iomem *)hose->cfg_data) + +- ((offset>>1) & 1), val); +- break; +- +- default: +- out_le16((u16 __iomem *)hose->cfg_data, +- (u16)val); +- out_le16(((u16 __iomem *)hose->cfg_data) + 1, +- (u16)(val>>16)); +- break; +- } +- } +- else +-#endif +- { +- if (len != 4) { +- value = in_le32(hose->cfg_data); +- +- offset = (offset & 0x3) << 3; +- mask = (0xffffffff >> (32 - (len << 3))); +- mask <<= offset; +- +- value &= ~mask; +- val = value | ((val << offset) & mask); +- } +- +- out_le32(hose->cfg_data, val); +- } +- mb(); +- +- out_be32(hose->cfg_addr, 0); +- mb(); +- +- return PCIBIOS_SUCCESSFUL; +-} +- +-static struct pci_ops mpc52xx_pci_ops = { +- .read = mpc52xx_pci_read_config, +- .write = mpc52xx_pci_write_config +-}; +- +- +-static void __init +-mpc52xx_pci_setup(struct pci_controller *hose, +- struct mpc52xx_pci __iomem *pci_regs) +-{ +- struct resource *res; +- u32 tmp; +- int iwcr0 = 0, iwcr1 = 0, iwcr2 = 0; +- +- pr_debug("mpc52xx_pci_setup(hose=%p, pci_regs=%p)\n", hose, pci_regs); +- +- /* pci_process_bridge_OF_ranges() found all our addresses for us; +- * now store them in the right places */ +- hose->cfg_addr = &pci_regs->car; +- hose->cfg_data = hose->io_base_virt; +- hose->io_base_virt = ioremap(hose->io_base_phys, +- hose->io_resource.end + 1 - +- hose->io_resource.start); +- isa_io_base = (unsigned long) hose->io_base_virt; +- +- /* Control regs */ +- tmp = in_be32(&pci_regs->scr); +- tmp |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; +- out_be32(&pci_regs->scr, tmp); +- +- /* Memory windows */ +- res = &hose->mem_resources[0]; +- if (res->flags) { +- pr_debug("mem_resource[0] = {.start=%x, .end=%x, .flags=%lx}\n", +- res->start, res->end, res->flags); +- out_be32(&pci_regs->iw0btar, +- MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start, +- res->end - res->start + 1)); +- iwcr0 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM; +- if (res->flags & IORESOURCE_PREFETCH) +- iwcr0 |= MPC52xx_PCI_IWCR_READ_MULTI; +- else +- iwcr0 |= MPC52xx_PCI_IWCR_READ; +- } +- +- res = &hose->mem_resources[1]; +- if (res->flags) { +- pr_debug("mem_resource[1] = {.start=%x, .end=%x, .flags=%lx}\n", +- res->start, res->end, res->flags); +- out_be32(&pci_regs->iw1btar, +- MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start, +- res->end - res->start + 1)); +- iwcr1 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM; +- if (res->flags & IORESOURCE_PREFETCH) +- iwcr1 |= MPC52xx_PCI_IWCR_READ_MULTI; +- else +- iwcr1 |= MPC52xx_PCI_IWCR_READ; +- } +- +- /* IO resources */ +- res = &hose->io_resource; +- if (!res) { +- printk(KERN_ERR "%s: Didn't find IO resources\n", __FILE__); +- return; +- } +- pr_debug(".io_resource={.start=%x,.end=%x,.flags=%lx} " +- ".io_base_phys=0x%p\n", +- res->start, res->end, res->flags, (void*)hose->io_base_phys); +- out_be32(&pci_regs->iw2btar, +- MPC52xx_PCI_IWBTAR_TRANSLATION(hose->io_base_phys, +- res->start, +- res->end - res->start + 1)); +- iwcr2 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_IO; +- +- /* Set all the IWCR fields at once; they're in the same reg */ +- out_be32(&pci_regs->iwcr, MPC52xx_PCI_IWCR_PACK(iwcr0, iwcr1, iwcr2)); +- +- out_be32(&pci_regs->tbatr0, +- MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_IO ); +- out_be32(&pci_regs->tbatr1, +- MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_MEM ); +- +- out_be32(&pci_regs->tcr, MPC52xx_PCI_TCR_LD); +- +-#if 0 +- /* Reset the exteral bus ( internal PCI controller is NOT resetted ) */ +- /* Not necessary and can be a bad thing if for example the bootloader +- is displaying a splash screen or ... Just left here for +- documentation purpose if anyone need it */ +- tmp = in_be32(&pci_regs->gscr); +- out_be32(&pci_regs->gscr, tmp | MPC52xx_PCI_GSCR_PR); +- udelay(50); +- out_be32(&pci_regs->gscr, tmp & ~MPC52xx_PCI_GSCR_PR); +-#endif +-} +- +-static void +-mpc52xx_pci_fixup_resources(struct pci_dev *dev) +-{ +- int i; +- +- pr_debug("mpc52xx_pci_fixup_resources() %.4x:%.4x\n", +- dev->vendor, dev->device); +- +- /* We don't rely on boot loader for PCI and resets all +- devices */ +- for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { +- struct resource *res = &dev->resource[i]; +- if (res->end > res->start) { /* Only valid resources */ +- res->end -= res->start; +- res->start = 0; +- res->flags |= IORESOURCE_UNSET; +- } +- } +- +- /* The PCI Host bridge of MPC52xx has a prefetch memory resource +- fixed to 1Gb. Doesn't fit in the resource system so we remove it */ +- if ( (dev->vendor == PCI_VENDOR_ID_MOTOROLA) && +- ( dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200 +- || dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200B) ) { +- struct resource *res = &dev->resource[1]; +- res->start = res->end = res->flags = 0; +- } +-} +- +-int __init +-mpc52xx_add_bridge(struct device_node *node) +-{ +- int len; +- struct mpc52xx_pci __iomem *pci_regs; +- struct pci_controller *hose; +- const int *bus_range; +- struct resource rsrc; +- +- pr_debug("Adding MPC52xx PCI host bridge %s\n", node->full_name); +- +- pci_assign_all_buses = 1; +- +- if (of_address_to_resource(node, 0, &rsrc) != 0) { +- printk(KERN_ERR "Can't get %s resources\n", node->full_name); +- return -EINVAL; +- } +- +- bus_range = get_property(node, "bus-range", &len); +- if (bus_range == NULL || len < 2 * sizeof(int)) { +- printk(KERN_WARNING "Can't get %s bus-range, assume bus 0\n", +- node->full_name); +- bus_range = NULL; +- } +- +- /* There are some PCI quirks on the 52xx, register the hook to +- * fix them. */ +- ppc_md.pcibios_fixup_resources = mpc52xx_pci_fixup_resources; +- +- /* Alloc and initialize the pci controller. Values in the device +- * tree are needed to configure the 52xx PCI controller. Rather +- * than parse the tree here, let pci_process_bridge_OF_ranges() +- * do it for us and extract the values after the fact */ +- hose = pcibios_alloc_controller(); +- if (!hose) +- return -ENOMEM; +- +- hose->arch_data = node; +- hose->set_cfg_type = 1; +- +- hose->first_busno = bus_range ? bus_range[0] : 0; +- hose->last_busno = bus_range ? bus_range[1] : 0xff; +- +- hose->bus_offset = 0; +- hose->ops = &mpc52xx_pci_ops; +- +- pci_regs = ioremap(rsrc.start, rsrc.end - rsrc.start + 1); +- if (!pci_regs) +- return -ENOMEM; +- +- pci_process_bridge_OF_ranges(hose, node, 0); +- +- /* Finish setting up PCI using values obtained by +- * pci_proces_bridge_OF_ranges */ +- mpc52xx_pci_setup(hose, pci_regs); +- +- return 0; +-} +-- +1.4.4.2 + diff --git a/debian/patches/features/powerpc/efika/0031-sound-Add-support-for-the-MPC52xx-PSC-AC97-Link.txt b/debian/patches/features/powerpc/efika/0031-sound-Add-support-for-the-MPC52xx-PSC-AC97-Link.txt new file mode 100644 index 000000000..5e8d5a268 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0031-sound-Add-support-for-the-MPC52xx-PSC-AC97-Link.txt @@ -0,0 +1,828 @@ +From 46e8903e34759728afd11dd11c481e6a94e6b06d Mon Sep 17 00:00:00 2001 +From: Sylvain Munaut +Date: Mon, 18 Dec 2006 22:51:38 +0100 +Subject: [PATCH] [PATCH] sound: Add support for the MPC52xx PSC AC97 Link + +Messy driver, to be cleaned ... a lot ... + +Signed-off-by: Sylvain Munaut +--- + include/asm-ppc/mpc52xx_psc.h | 10 +- + sound/ppc/Kconfig | 16 + + sound/ppc/Makefile | 3 + + sound/ppc/mpc52xx_ac97.c | 738 +++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 765 insertions(+), 2 deletions(-) + +diff --git a/include/asm-ppc/mpc52xx_psc.h b/include/asm-ppc/mpc52xx_psc.h +index 9d850b2..c82b8d4 100644 +--- a/include/asm-ppc/mpc52xx_psc.h ++++ b/include/asm-ppc/mpc52xx_psc.h +@@ -28,6 +28,10 @@ + #define MPC52xx_PSC_MAXNUM 6 + + /* Programmable Serial Controller (PSC) status register bits */ ++#define MPC52xx_PSC_SR_UNEX_RX 0x0001 ++#define MPC52xx_PSC_SR_DATA_VAL 0x0002 ++#define MPC52xx_PSC_SR_DATA_OVR 0x0004 ++#define MPC52xx_PSC_SR_CMDSEND 0x0008 + #define MPC52xx_PSC_SR_CDE 0x0080 + #define MPC52xx_PSC_SR_RXRDY 0x0100 + #define MPC52xx_PSC_SR_RXFULL 0x0200 +@@ -132,8 +136,10 @@ struct mpc52xx_psc { + u8 reserved5[3]; + u8 ctlr; /* PSC + 0x1c */ + u8 reserved6[3]; +- u16 ccr; /* PSC + 0x20 */ +- u8 reserved7[14]; ++ u32 ccr; /* PSC + 0x20 */ ++ u32 ac97_slots; /* PSC + 0x24 */ ++ u32 ac97_cmd; /* PSC + 0x28 */ ++ u32 ac97_data; /* PSC + 0x2c */ + u8 ivr; /* PSC + 0x30 */ + u8 reserved8[3]; + u8 ip; /* PSC + 0x34 */ +diff --git a/sound/ppc/Kconfig b/sound/ppc/Kconfig +index a3fb149..afd58f7 100644 +--- a/sound/ppc/Kconfig ++++ b/sound/ppc/Kconfig +@@ -33,3 +33,19 @@ config SND_POWERMAC_AUTO_DRC + option. + + endmenu ++ ++ ++# ALSA ppc drivers ++ ++menu "ALSA PPC devices" ++ depends on SND!=n && PPC ++ ++config SND_PPC_MPC52xx_AC97 ++ tristate "Freescale MPC52xx AC97 interface support" ++ depends on SND && PPC_MPC52xx ++ select SND_AC97_CODEC ++ help ++ Say Y or M if you want to support any AC97 codec attached to ++ the Freescqle MPC52xx AC97 interface. ++ ++endmenu +diff --git a/sound/ppc/Makefile b/sound/ppc/Makefile +index 4d95c65..c29cb9b 100644 +--- a/sound/ppc/Makefile ++++ b/sound/ppc/Makefile +@@ -4,6 +4,9 @@ + # + + snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o keywest.o beep.o ++snd-mpc52xx-ac97-objs := mpc52xx_ac97.o + + # Toplevel Module Dependency + obj-$(CONFIG_SND_POWERMAC) += snd-powermac.o ++ ++obj-$(CONFIG_SND_PPC_MPC52xx_AC97) += snd-mpc52xx-ac97.o +diff --git a/sound/ppc/mpc52xx_ac97.c b/sound/ppc/mpc52xx_ac97.c +new file mode 100644 +index 0000000..a4f008e +--- /dev/null ++++ b/sound/ppc/mpc52xx_ac97.c +@@ -0,0 +1,738 @@ ++/* ++ * Driver for the PSC of the Freescale MPC52xx configured as AC97 interface ++ * ++ * ++ * Copyright (C) 2006 Sylvain Munaut ++ * ++ * 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. ++ */ ++ ++#define DEBUG ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++ ++#define DRV_NAME "mpc52xx-psc-ac97" ++ ++ ++/* ======================================================================== */ ++/* Structs / Defines */ ++/* ======================================================================== */ ++ ++/* Private structure */ ++struct mpc52xx_ac97_priv { ++ struct device *dev; ++ resource_size_t mem_start; ++ resource_size_t mem_len; ++ int irq; ++ struct mpc52xx_psc __iomem *psc; ++ struct snd_card *card; ++ struct snd_pcm *pcm; ++ struct snd_ac97 *ac97; ++ ++ struct snd_pcm_substream *substream_playback; ++ unsigned int buf_pos; ++}; ++ ++/* Register bit definition (AC97 mode specific) */ ++#define PSC_AC97_SLOT_BIT(n) (1<<(12-n)) ++#define PSC_AC97_SLOTS_XMIT_SHIFT 16 ++#define PSC_AC97_SLOTS_RECV_SHIFT 0 ++ ++ ++ ++/* ======================================================================== */ ++/* ISR routine */ ++/* ======================================================================== */ ++ ++static irqreturn_t ++mpc52xx_ac97_irq(int irq, void *dev_id) ++{ ++ struct mpc52xx_ac97_priv *priv = dev_id; ++ ++ static int icnt = 0; ++ #if 0 ++ { ++ unsigned int val; ++// val = in_be32(&priv->psc->ac97_data); ++ printk(KERN_INFO "mpc52xx_ac97_irq fired (isr=%04x, status=%04x) %08x\n", in_be16(&priv->psc->mpc52xx_psc_imr), in_be16(&priv->psc->mpc52xx_psc_status), val); ++ out_8(&priv->psc->command,MPC52xx_PSC_RST_ERR_STAT); ++ } ++ #endif ++ ++ /* Anti Crash during dev ;) */ ++ #if 0 ++ if ((icnt++) > 50000) ++ out_be16(&priv->psc->mpc52xx_psc_imr, 0); ++ #endif ++ ++ /* Copy 64 data into the buffer */ ++ if (in_be16(&priv->psc->mpc52xx_psc_imr) & 0x0100) { ++ if (priv->substream_playback) { ++ struct snd_pcm_runtime *rt; ++ ++ rt = priv->substream_playback->runtime; ++ ++ if (snd_pcm_playback_hw_avail(rt) < bytes_to_frames(rt,128)) { ++ int i; ++ /* Push silence */ ++ for (i=0; i<64; i++) ++ out_be32(&priv->psc->mpc52xx_psc_buffer_32, 0x00000800); ++ printk(KERN_DEBUG "pushed silence ...\n"); ++ } else { ++ int i; ++ unsigned short *data; ++ ++ data = (unsigned short *) ++ (&rt->dma_area[frames_to_bytes(rt, priv->buf_pos)]); ++ ++ for (i=0; i<64; i++) ++ out_be32(&priv->psc->mpc52xx_psc_buffer_32, ++ (((unsigned int)data[i]) << 16) | 0x00000000); ++ /* Setting the sof bit looks useless */ ++ ++ priv->buf_pos += bytes_to_frames(rt,128);; ++ if (priv->buf_pos >= rt->buffer_size) ++ priv->buf_pos = 0; ++ ++ snd_pcm_period_elapsed(priv->substream_playback); ++ } ++ } else { ++ out_be16(&priv->psc->mpc52xx_psc_imr, 0); ++ printk(KERN_DEBUG "Interrupt with no stream ...\n"); ++ } ++ } else { ++ printk(KERN_ERR "Spurious int\n"); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++ ++/* ======================================================================== */ ++/* PCM interface */ ++/* ======================================================================== */ ++ ++/* HW desc */ ++ ++static struct snd_pcm_hardware mpc52xx_ac97_hw = { ++ .info = SNDRV_PCM_INFO_INTERLEAVED | ++ SNDRV_PCM_INFO_MMAP | ++ SNDRV_PCM_INFO_MMAP_VALID, ++ .formats = SNDRV_PCM_FMTBIT_S16_BE, ++ .rates = SNDRV_PCM_RATE_8000_48000, ++ .rate_min = 8000, ++ .rate_max = 48000, ++ .channels_min = 1, ++ .channels_max = 2, /* Support for more ? */ ++ .buffer_bytes_max = 128*1024, ++ .period_bytes_min = 128, /* 32, */ ++ .period_bytes_max = 128, /* 16*1024, */ ++ .periods_min = 8, ++ .periods_max = 256, ++ .fifo_size = 512, ++}; ++ ++ ++/* Playback */ ++ ++static int ++mpc52xx_ac97_playback_open(struct snd_pcm_substream *substream) ++{ ++ struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; ++ ++ dev_dbg(priv->dev, "mpc52xx_ac97_playback_open(%p)\n", substream); ++ ++ substream->runtime->hw = mpc52xx_ac97_hw; ++ ++ priv->substream_playback = substream; ++ priv->buf_pos = 0; /* FIXME Do that where ? */ ++ ++ return 0; /* FIXME */ ++} ++ ++static int ++mpc52xx_ac97_playback_close(struct snd_pcm_substream *substream) ++{ ++ struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; ++ dev_dbg(priv->dev, "mpc52xx_ac97_playback_close(%p)\n", substream); ++ priv->substream_playback = NULL; ++ return 0; /* FIXME */ ++} ++ ++static int ++mpc52xx_ac97_playback_prepare(struct snd_pcm_substream *substream) ++{ ++ struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; ++ ++ dev_dbg(priv->dev, "mpc52xx_ac97_playback_prepare(%p)\n", substream); ++ ++ /* FIXME, need a spinlock to protect access */ ++ if (substream->runtime->channels == 1) ++ out_be32(&priv->psc->ac97_slots, 0x01000000); ++ else ++ out_be32(&priv->psc->ac97_slots, 0x03000000); ++ ++ snd_ac97_set_rate(priv->ac97, AC97_PCM_FRONT_DAC_RATE, substream->runtime->rate); ++ ++ return 0; /* FIXME */ ++} ++ ++ ++/* Capture */ ++ ++static int ++mpc52xx_ac97_capture_open(struct snd_pcm_substream *substream) ++{ ++ struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; ++ return 0; /* FIXME */ ++} ++ ++static int ++mpc52xx_ac97_capture_close(struct snd_pcm_substream *substream) ++{ ++ struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; ++ return 0; /* FIXME */ ++} ++ ++static int ++mpc52xx_ac97_capture_prepare(struct snd_pcm_substream *substream) ++{ ++ struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; ++ return 0; /* FIXME */ ++} ++ ++ ++/* Common */ ++ ++static int ++mpc52xx_ac97_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; ++ int rv; ++ ++ dev_dbg(priv->dev, "mpc52xx_ac97_hw_params(%p)\n", substream); ++ ++ rv = snd_pcm_lib_malloc_pages(substream, ++ params_buffer_bytes(params)); ++ if (rv < 0) { ++ printk(KERN_ERR "hw params failes\n"); /* FIXME */ ++ return rv; ++ } ++ ++ printk(KERN_DEBUG "%d %d %d\n", params_buffer_bytes(params), params_period_bytes(params), params_periods(params)); ++ ++ ++ return 0; ++} ++ ++static int ++mpc52xx_ac97_hw_free(struct snd_pcm_substream *substream) ++{ ++ struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; ++ ++ dev_dbg(priv->dev, "mpc52xx_ac97_hw_free(%p)\n", substream); ++ ++ return snd_pcm_lib_free_pages(substream); ++} ++ ++static int ++mpc52xx_ac97_trigger(struct snd_pcm_substream *substream, int cmd) ++{ ++ struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; ++ int rv = 0; ++ ++ dev_dbg(priv->dev, "mpc52xx_ac97_trigger(%p,%d)\n", substream, cmd); ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ /* Enable TX interrupt */ ++ out_be16(&priv->psc->mpc52xx_psc_imr, 0x0100); // 0x0100 ++ ++ break; ++ ++ case SNDRV_PCM_TRIGGER_STOP: ++ /* Disable TX interrupt */ ++ out_be16(&priv->psc->mpc52xx_psc_imr, 0x0000); ++ ++ break; ++ ++ default: ++ rv = -EINVAL; ++ } ++ ++ /* FIXME */ ++ return rv; ++} ++ ++static snd_pcm_uframes_t ++mpc52xx_ac97_pointer(struct snd_pcm_substream *substream) ++{ ++ struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; ++ ++// dev_dbg(priv->dev, "mpc52xx_ac97_pointer(%p)\n", substream); ++ ++ if (substream->runtime->channels == 1) ++ return priv->buf_pos; /* FIXME */ ++ else ++ return priv->buf_pos >> 1; /* FIXME */ ++} ++ ++ ++/* Ops */ ++ ++static struct snd_pcm_ops mpc52xx_ac97_playback_ops = { ++ .open = mpc52xx_ac97_playback_open, ++ .close = mpc52xx_ac97_playback_close, ++ .ioctl = snd_pcm_lib_ioctl, ++ .hw_params = mpc52xx_ac97_hw_params, ++ .hw_free = mpc52xx_ac97_hw_free, ++ .prepare = mpc52xx_ac97_playback_prepare, ++ .trigger = mpc52xx_ac97_trigger, ++ .pointer = mpc52xx_ac97_pointer, ++}; ++ ++static struct snd_pcm_ops mpc52xx_ac97_capture_ops = { ++ .open = mpc52xx_ac97_capture_open, ++ .close = mpc52xx_ac97_capture_close, ++ .ioctl = snd_pcm_lib_ioctl, ++ .hw_params = mpc52xx_ac97_hw_params, ++ .hw_free = mpc52xx_ac97_hw_free, ++ .prepare = mpc52xx_ac97_capture_prepare, ++ .trigger = mpc52xx_ac97_trigger, ++ .pointer = mpc52xx_ac97_pointer, ++}; ++ ++ ++/* ======================================================================== */ ++/* AC97 Bus interface */ ++/* ======================================================================== */ ++ ++static unsigned short ++mpc52xx_ac97_bus_read(struct snd_ac97 *ac97, unsigned short reg) ++{ ++ struct mpc52xx_ac97_priv *priv = ac97->private_data; ++ int timeout; ++ unsigned int val; ++ ++ dev_dbg(priv->dev, "ac97 read: reg %04x\n", reg); ++ ++ /* Wait for it to be ready */ ++ timeout = 1000; ++ while ((--timeout) && (in_be16(&priv->psc->mpc52xx_psc_status) & ++ MPC52xx_PSC_SR_CMDSEND) ) ++ udelay(10); ++ ++ if (!timeout) { ++ printk(KERN_ERR DRV_NAME ": timeout on ac97 bus (rdy)\n"); ++ return 0xffff; ++ } ++ ++ /* Do the read */ ++ out_be32(&priv->psc->ac97_cmd, (1<<31) | ((reg & 0x7f) << 24)); ++ ++ /* Wait for the answer */ ++ timeout = 1000; ++ while ((--timeout) && !(in_be16(&priv->psc->mpc52xx_psc_status) & ++ MPC52xx_PSC_SR_DATA_VAL) ) ++ udelay(10); ++ ++ if (!timeout) { ++ printk(KERN_ERR DRV_NAME ": timeout on ac97 read (val)\n"); ++ return 0xffff; ++ } ++ ++ /* Get the data */ ++ val = in_be32(&priv->psc->ac97_data); ++ if ( ((val>>24) & 0x7f) != reg ) { ++ printk(KERN_ERR DRV_NAME ": reg echo error on ac97 read\n"); ++ return 0xffff; ++ } ++ val = (val >> 8) & 0xffff; ++ ++ dev_dbg(priv->dev, "ac97 read ok: reg %04x val %04x\n", ++ reg, val); ++ ++ return (unsigned short) val; ++} ++ ++static void ++mpc52xx_ac97_bus_write(struct snd_ac97 *ac97, ++ unsigned short reg, unsigned short val) ++{ ++ struct mpc52xx_ac97_priv *priv = ac97->private_data; ++ int timeout; ++ ++ dev_dbg(priv->dev, "ac97 write: reg %04x val %04x\n", ++ reg, val); ++ ++ /* Wait for it to be ready */ ++ timeout = 1000; ++ while ((--timeout) && (in_be16(&priv->psc->mpc52xx_psc_status) & ++ MPC52xx_PSC_SR_CMDSEND) ) ++ udelay(10); ++ ++ if (!timeout) { ++ printk(KERN_ERR DRV_NAME ": timeout on ac97 write\n"); ++ return; ++ } ++ ++ /* Write data */ ++ out_be32(&priv->psc->ac97_cmd, ((reg & 0x7f) << 24) | (val << 8)); ++} ++ ++static void ++mpc52xx_ac97_bus_reset(struct snd_ac97 *ac97) ++{ ++ struct mpc52xx_ac97_priv *priv = ac97->private_data; ++ ++ dev_dbg(priv->dev, "ac97 codec reset\n"); ++ ++ /* Do a cold reset */ ++ out_8(&priv->psc->op1, 0x03); ++ udelay(10); ++ out_8(&priv->psc->op0, 0x02); ++ udelay(50); ++ ++ /* PSC recover from cold reset (cfr user manual, not sure if useful) */ ++ out_be32(&priv->psc->sicr, in_be32(&priv->psc->sicr)); ++} ++ ++ ++static struct snd_ac97_bus_ops mpc52xx_ac97_bus_ops = { ++ .read = mpc52xx_ac97_bus_read, ++ .write = mpc52xx_ac97_bus_write, ++ .reset = mpc52xx_ac97_bus_reset, ++}; ++ ++ ++/* ======================================================================== */ ++/* Sound driver setup */ ++/* ======================================================================== */ ++ ++static int ++mpc52xx_ac97_setup_pcm(struct mpc52xx_ac97_priv *priv) ++{ ++ int rv; ++ ++ rv = snd_pcm_new(priv->card, DRV_NAME "-pcm", 0, 1, 1, &priv->pcm); ++ if (rv) { ++ printk(KERN_ERR DRV_NAME ": snd_pcm_new failed\n"); ++ return rv; ++ } ++ ++ rv = snd_pcm_lib_preallocate_pages_for_all(priv->pcm, ++ SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL), ++ 128*1024, 128*1024); ++ if (rv) { ++ printk(KERN_ERR DRV_NAME ++ ": snd_pcm_lib_preallocate_pages_for_all failed\n"); ++ return rv; ++ } ++ ++ snd_pcm_set_ops(priv->pcm, SNDRV_PCM_STREAM_PLAYBACK, ++ &mpc52xx_ac97_playback_ops); ++ snd_pcm_set_ops(priv->pcm, SNDRV_PCM_STREAM_CAPTURE, ++ &mpc52xx_ac97_capture_ops); ++ ++ priv->pcm->private_data = priv; ++ priv->pcm->info_flags = 0; ++ ++ strcpy(priv->pcm->name, "Freescale MPC52xx PSC-AC97 PCM"); ++ ++ return 0; ++} ++ ++static int ++mpc52xx_ac97_setup_mixer(struct mpc52xx_ac97_priv *priv) ++{ ++ struct snd_ac97_bus *ac97_bus; ++ struct snd_ac97_template ac97_template; ++ int rv; ++ ++ rv = snd_ac97_bus(priv->card, 0, &mpc52xx_ac97_bus_ops, NULL, &ac97_bus); ++ if (rv) { ++ printk(KERN_ERR DRV_NAME ": snd_ac97_bus failed\n"); ++ return rv; ++ } ++ ++ memset(&ac97_template, 0, sizeof(struct snd_ac97_template)); ++ ac97_template.private_data = priv; ++ ++ rv = snd_ac97_mixer(ac97_bus, &ac97_template, &priv->ac97); ++ if (rv) { ++ printk(KERN_ERR DRV_NAME ": snd_ac97_mixer failed\n"); ++ return rv; ++ } ++ ++ return 0; ++} ++ ++ ++static int ++mpc52xx_ac97_hwinit(struct mpc52xx_ac97_priv *priv) ++{ ++ /* Reset everything first by safety */ ++ out_8(&priv->psc->command,MPC52xx_PSC_RST_RX); ++ out_8(&priv->psc->command,MPC52xx_PSC_RST_TX); ++ out_8(&priv->psc->command,MPC52xx_PSC_RST_ERR_STAT); ++ ++ /* Do a cold reset of codec */ ++ out_8(&priv->psc->op1, 0x03); ++ udelay(10); ++ out_8(&priv->psc->op0, 0x02); ++ udelay(50); ++ ++ /* Configure AC97 enhanced mode */ ++ out_be32(&priv->psc->sicr, 0x03010000); ++ ++ /* No slots active */ ++ out_be32(&priv->psc->ac97_slots, 0x00000000); ++ ++ /* No IRQ */ ++ out_be16(&priv->psc->mpc52xx_psc_imr, 0x0000); ++ ++ /* FIFO levels */ ++ out_8(&priv->psc->rfcntl, 0x07); ++ out_8(&priv->psc->tfcntl, 0x07); ++ out_be16(&priv->psc->rfalarm, 0x80); ++ out_be16(&priv->psc->tfalarm, 0x80); ++ ++ /* Go */ ++ out_8(&priv->psc->command,MPC52xx_PSC_TX_ENABLE); ++ out_8(&priv->psc->command,MPC52xx_PSC_RX_ENABLE); ++ ++ return 0; ++} ++ ++static int ++mpc52xx_ac97_hwshutdown(struct mpc52xx_ac97_priv *priv) ++{ ++ /* No IRQ */ ++ out_be16(&priv->psc->mpc52xx_psc_imr, 0x0000); ++ ++ /* Disable TB & RX */ ++ out_8(&priv->psc->command,MPC52xx_PSC_RST_RX); ++ out_8(&priv->psc->command,MPC52xx_PSC_RST_TX); ++ ++ /* FIXME : Reset or put codec in low power ? */ ++ ++ return 0; ++} ++ ++ ++/* ======================================================================== */ ++/* OF Platform Driver */ ++/* ======================================================================== */ ++ ++static int __devinit ++mpc52xx_ac97_probe(struct of_device *op, const struct of_device_id *match) ++{ ++ struct device_node *dn = op->node; ++ struct mpc52xx_ac97_priv *priv; ++ struct snd_card *card; ++ struct resource res; ++ int rv; ++ ++ dev_dbg(&op->dev, "probing MPC52xx PSC AC97 driver\n"); ++ ++ /* Get card structure */ ++ rv = -ENOMEM; ++ card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, ++ THIS_MODULE, sizeof(struct mpc52xx_ac97_priv)); ++ if (!card) ++ goto err_early; ++ ++ priv = card->private_data; ++ ++ /* Init our private structure */ ++ priv->card = card; ++ priv->dev = &op->dev; ++ ++ /* Get resources (mem,irq,...) */ ++ rv = of_address_to_resource(dn, 0, &res); ++ if (rv) ++ goto err_early; ++ ++ priv->mem_start = res.start; ++ priv->mem_len = res.end - res.start + 1; ++ ++ if (!request_mem_region(priv->mem_start, priv->mem_len, DRV_NAME)) { ++ printk(KERN_ERR DRV_NAME ": request_mem_region failed\n"); ++ rv = -EBUSY; ++ goto err_early; ++ } ++ ++ priv->psc = ioremap(priv->mem_start, priv->mem_len); ++ if (!priv->psc) { ++ printk(KERN_ERR DRV_NAME ": ioremap failed\n"); ++ rv = -ENOMEM; ++ goto err_iomap; ++ } ++ ++ priv->irq = irq_of_parse_and_map(dn, 0); ++ if (priv->irq == NO_IRQ) { ++ printk(KERN_ERR DRV_NAME ": irq_of_parse_and_map failed\n"); ++ rv = -EBUSY; ++ goto err_irqmap; ++ } ++ ++ /* Low level HW Init */ ++ mpc52xx_ac97_hwinit(priv); ++ ++ /* Request IRQ now that we're 'stable' */ ++ rv = request_irq(priv->irq, mpc52xx_ac97_irq, 0, DRV_NAME, priv); ++ if (rv < 0) { ++ printk(KERN_ERR DRV_NAME ": request_irq failed\n"); ++ goto err_irqreq; ++ } ++ ++ /* Prepare sound stuff */ ++ rv = mpc52xx_ac97_setup_mixer(priv); ++ if (rv) ++ goto err_late; ++ ++ rv = mpc52xx_ac97_setup_pcm(priv); ++ if (rv) ++ goto err_late; ++ ++ /* Finally register the card */ ++ snprintf(card->shortname, sizeof(card->shortname), DRV_NAME); ++ snprintf(card->longname, sizeof(card->longname), ++ "Freescale MPC52xx PSC-AC97 (%s)", card->mixername); ++ ++ rv = snd_card_register(card); ++ if (rv) { ++ printk(KERN_ERR DRV_NAME ": snd_card_register failed\n"); ++ goto err_late; ++ } ++ ++ dev_set_drvdata(&op->dev, priv); ++ ++ return 0; ++ ++err_late: ++ free_irq(priv->irq, priv); ++err_irqreq: ++ mpc52xx_ac97_hwshutdown(priv); ++ irq_dispose_mapping(priv->irq); ++err_irqmap: ++ iounmap(priv->psc); ++err_iomap: ++ release_mem_region(priv->mem_start, priv->mem_len); ++err_early: ++ if (card) ++ snd_card_free(card); ++ return rv; ++} ++ ++static int ++mpc52xx_ac97_remove(struct of_device *op) ++{ ++ struct mpc52xx_ac97_priv *priv; ++ ++ dev_dbg(&op->dev, "removing MPC52xx PSC AC97 driver\n"); ++ ++ priv = dev_get_drvdata(&op->dev); ++ if (priv) { ++ /* Sound subsys shutdown */ ++ snd_card_free(priv->card); ++ ++ /* Low level HW shutdown */ ++ mpc52xx_ac97_hwshutdown(priv); ++ ++ /* Release resources */ ++ iounmap(priv->psc); ++ free_irq(priv->irq, priv); ++ irq_dispose_mapping(priv->irq); ++ release_mem_region(priv->mem_start, priv->mem_len); ++ } ++ ++ dev_set_drvdata(&op->dev, NULL); ++ ++ return 0; ++} ++ ++ ++static struct of_device_id mpc52xx_ac97_of_match[] = { ++ { ++/* .type = "ac97", FIXME Efika ... */ ++ .compatible = "mpc5200b-psc-ac97", /* B only for now */ ++ }, ++}; ++/* Prevent autoload during developpment phase ... */ ++/* MODULE_DEVICE_TABLE(of, mpc52xx_ac97_of_match); */ ++ ++ ++static struct of_platform_driver mpc52xx_ac97_of_driver = { ++ .owner = THIS_MODULE, ++ .name = DRV_NAME, ++ .match_table = mpc52xx_ac97_of_match, ++ .probe = mpc52xx_ac97_probe, ++ .remove = mpc52xx_ac97_remove, ++ .driver = { ++ .name = DRV_NAME, ++ }, ++}; ++ ++ ++/* ======================================================================== */ ++/* Module */ ++/* ======================================================================== */ ++ ++static int __init ++mpc52xx_ac97_init(void) ++{ ++ int rv; ++ ++ /* FIXME BIG FAT EFIKA HACK */ ++ { ++ void *mbar; ++ mbar = ioremap(0xf0000000, 0x100000); ++ printk(KERN_INFO "EFIKA HACK: port_config %08x\n", in_be32(mbar + 0xb00)); ++ out_be32(mbar + 0xb00, 0x01051124); ++ printk(KERN_INFO "EFIKA HACK: port_config %08x\n", in_be32(mbar + 0xb00)); ++ iounmap(mbar); ++ } ++ /* ------------------------ */ ++ ++ printk(KERN_INFO "Sound: MPC52xx PSC AC97 driver\n"); ++ ++ rv = of_register_platform_driver(&mpc52xx_ac97_of_driver); ++ if (rv) { ++ printk(KERN_ERR DRV_NAME ": " ++ "of_register_platform_driver failed (%i)\n", rv); ++ return rv; ++ } ++ ++ return 0; ++} ++ ++static void __exit ++mpc52xx_ac97_exit(void) ++{ ++ of_unregister_platform_driver(&mpc52xx_ac97_of_driver); ++} ++ ++module_init(mpc52xx_ac97_init); ++module_exit(mpc52xx_ac97_exit); ++ ++MODULE_AUTHOR("Sylvain Munaut "); ++MODULE_DESCRIPTION(DRV_NAME ": Freescale MPC52xx PSC AC97 driver"); ++MODULE_LICENSE("GPL"); ++ +-- +1.4.4.2 + diff --git a/debian/patches/features/powerpc/efika/0033-Fix-the-bestcomm-interrupt-property-fixes-the-ethernet-driver.txt b/debian/patches/features/powerpc/efika/0033-Fix-the-bestcomm-interrupt-property-fixes-the-ethernet-driver.txt new file mode 100644 index 000000000..4ecb538ba --- /dev/null +++ b/debian/patches/features/powerpc/efika/0033-Fix-the-bestcomm-interrupt-property-fixes-the-ethernet-driver.txt @@ -0,0 +1,113 @@ +From 49029f815b10175dcec09152929d53efe0ed510c Mon Sep 17 00:00:00 2001 +From: Sven Luther +Date: Tue, 9 Jan 2007 11:12:51 +0100 +Subject: [PATCH] Fix the bestcomm interrupt property, fixes the ethernet driver. + +--- + arch/powerpc/kernel/prom_init.c | 85 +++++++++++++++++++++++++++++++++++++++ + 1 files changed, 85 insertions(+), 0 deletions(-) + +diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c +index 520ef42..a1cf18e 100644 +--- a/arch/powerpc/kernel/prom_init.c ++++ b/arch/powerpc/kernel/prom_init.c +@@ -2117,11 +2117,96 @@ static void __init fixup_device_tree_pmac(void) + #define fixup_device_tree_pmac() + #endif + ++#ifdef CONFIG_PPC_EFIKA ++/* The current fw of the Efika has a device tree needs quite a few ++ * fixups to be compliant with the mpc52xx bindings. It's currently ++ * unknown if it will ever be compliant (come on bPlan ...) so we do fixups. ++ * NOTE that we (barely) tolerate it because the EFIKA was out before ++ * the bindings were finished, for any new boards -> RTFM ! */ ++ ++struct subst_entry { ++ char *path; ++ char *property; ++ void *value; ++ int value_len; ++}; ++ ++static void __init fixup_device_tree_efika(void) ++{ ++ /* Substitution table */ ++ #define prop_cstr(x) x, sizeof(x) ++ int prop_sound_irq[3] = { 2, 2, 0 }; ++ int prop_bcomm_irq[48]; ++ struct subst_entry efika_subst_table[] = { ++ { "/", "device_type", prop_cstr("efika") }, ++ { "/builtin", "compatible", prop_cstr("soc") }, ++ { "/builtin/ata", "compatible", prop_cstr("mpc5200b-ata\0mpc52xx-ata"), }, ++ { "/builtin/bestcomm", "compatible", prop_cstr("mpc5200b-bestcomm\0mpc52xx-bestcomm") }, ++ { "/builtin/bestcomm", "interrupts", prop_bcomm_irq, sizeof(prop_bcomm_irq) }, ++ { "/builtin/ethernet", "compatible", prop_cstr("mpc5200b-fec\0mpc52xx-fec") }, ++ { "/builtin/pic", "compatible", prop_cstr("mpc5200b-pic\0mpc52xx-pic") }, ++ { "/builtin/serial", "compatible", prop_cstr("mpc5200b-psc-uart\0mpc52xx-psc-uart") }, ++ { "/builtin/sound", "compatible", prop_cstr("mpc5200b-psc-ac97\0mpc52xx-psc-ac97") }, ++ { "/builtin/sound", "interrupts", prop_sound_irq, sizeof(prop_sound_irq) }, ++ { "/builtin/sram", "compatible", prop_cstr("mpc5200b-sram\0mpc52xx-sram") }, ++ { "/builtin/sram", "device_type", prop_cstr("sram") }, ++ {} ++ }; ++ #undef prop_cstr ++ ++ /* Vars */ ++ u32 node; ++ char prop[64]; ++ int rv, i; ++ ++ /* Check if we're really running on a EFIKA */ ++ node = call_prom("finddevice", 1, 1, ADDR("/")); ++ if (!PHANDLE_VALID(node)) ++ return; ++ ++ rv = prom_getprop(node, "model", prop, sizeof(prop)); ++ if (rv == PROM_ERROR) ++ return; ++ if (strcmp(prop, "EFIKA5K2")) ++ return; ++ ++ prom_printf("Applying EFIKA device tree fixups\n"); ++ ++ /* Fill the prop_bcomm_irq */ ++ for (i=0; i<16; i++) { ++ prop_bcomm_irq[3*i ] = 3; ++ prop_bcomm_irq[3*i+1] = i; ++ prop_bcomm_irq[3*i+2] = 0; ++ } ++ ++ /* Process substitution table */ ++ for (i=0; efika_subst_table[i].path; i++) { ++ struct subst_entry *se = &efika_subst_table[i]; ++ ++ node = call_prom("finddevice", 1, 1, ADDR(se->path)); ++ if (!PHANDLE_VALID(node)) { ++ prom_printf("fixup_device_tree_efika: ", ++ "skipped entry %x - not found\n", i); ++ continue; ++ } ++ ++ rv = prom_setprop(node, se->path, se->property, ++ se->value, se->value_len ); ++ if (rv == PROM_ERROR) ++ prom_printf("fixup_device_tree_efika: ", ++ "skipped entry %x - setprop error\n", i); ++ } ++} ++#else ++#define fixup_device_tree_efika() ++#endif ++ + static void __init fixup_device_tree(void) + { + fixup_device_tree_maple(); + fixup_device_tree_chrp(); + fixup_device_tree_pmac(); ++ fixup_device_tree_efika(); + } + + static void __init prom_find_boot_cpu(void) +-- +1.4.4.2 + diff --git a/debian/patches/series/1~experimental.1 b/debian/patches/series/1~experimental.1 index 360fd33ac..11eb008d0 100644 --- a/debian/patches/series/1~experimental.1 +++ b/debian/patches/series/1~experimental.1 @@ -2,8 +2,8 @@ + debian/kernelvariables.patch + debian/doc-build-parallel.patch + debian/scripts-kconfig-reportoldconfig.patch -#+ debian/powerpc-mkvmlinuz-support-ppc.patch -#+ debian/powerpc-mkvmlinuz-support-powerpc.patch ++ debian/powerpc-mkvmlinuz-support-ppc.patch ++ debian/powerpc-mkvmlinuz-support-powerpc.patch + bugfix/powerpc/build-links.patch + bugfix/powerpc/mv643xx-hotplug-support.patch @@ -26,3 +26,35 @@ + features/arm/ixp4xx-net-driver-improve-mac-handling.patch + bugfix/Makefile-localversion-backup.patch + bugfix/drivers-bus_to_virt.patch + ++ features/powerpc/efika/0001-powerpc-serial-Dispose-irq-mapping-when-done-in-mpc52xx_serial.c.txt ++ features/powerpc/efika/0002-powerpc-52xx-Don-t-use-device_initcall-to-probe-of_platform_bus.txt ++ features/powerpc/efika/0004-powerpc-Use-common-52xx-of_platform-probe-code-for-EFIKA.txt ++ features/powerpc/efika/0005-powerpc-Restore-proper-link-order-in-platform.txt ++ features/powerpc/efika/0006-Rework-the-OHCI-quirk-mecanism-as-suggested-by-David.txt ++ features/powerpc/efika/0007-Implement-support-for-split-endian-OHCI.txt ++ features/powerpc/efika/0008-ohci-Rework-bus-glue-integration-to-allow-several-at-once.txt ++ features/powerpc/efika/0009-ohci-Add-support-for-OHCI-controller-on-the-of_platform-bus.txt ++ features/powerpc/efika/0010-libata-Add-support-for-the-MPC52xx-ATA-controller.txt ++ features/powerpc/efika/0011-ohci-Whitespace-and-typo-fix-in-ohci-ppc-of.c.txt ++ features/powerpc/efika/0012-ata-Fix-pata_mpc52xx.c-compatible-list.txt ++ features/powerpc/efika/0013-powerpc-serial-Fix-mpc52xx_uart.c-compatible-list.txt ++ features/powerpc/efika/0014-powerpc-Small-cleanup-of-EFIKA-platform.txt ++ features/powerpc/efika/0015-powerpc-Add-a-unified-uevent-handler-for-bus-based-on-of_device.txt ++ features/powerpc/efika/0016-macintosh-Use-the-new-of_device-common-uevent-handler.txt ++ features/powerpc/efika/0017-powerpc-Add-uevent-handler-for-of_platform_bus.txt ++ features/powerpc/efika/0018-powerpc-Add-uevent-handler-for-ibmebus.txt ++ features/powerpc/efika/0019-MPC5200-Bestcomm-platform-driver.txt ++ features/powerpc/efika/0020-Fec-MPC5200-eth-driver.txt ++ features/powerpc/efika/0021-POWERPC-Copy-bestcomm-support-files-into-arch-powerpc.txt ++ features/powerpc/efika/0022-MPC52xx-PCI-now-working-on-lite5200.-ugly-but-working.txt ++ features/powerpc/efika/0023-POWERPC-Make-FEC-work-on-the-lite5200.txt ++ features/powerpc/efika/0024-Add-missing-function-prototype.txt ++ features/powerpc/efika/0025-POWERPC-Misc-EFIKA-fixups-for-rtas-chrp.txt ++ features/powerpc/efika/0026-POWERPC-Cleanup-mpc52xx-PCI-support.txt ++ features/powerpc/efika/0027-POWERPC-Change-name-of-mpc52xx-pci-support-file-in-Makefile.txt ++ features/powerpc/efika/0028-POWERPC-Change-link-order-so-mpc52xx-fec-always-shows-up-as-eth0.txt ++ features/powerpc/efika/0029-POWERPC-Fixup-pr_print-format-for-mpc52xx-pci-support.txt ++ features/powerpc/efika/0030-POWERPC-Add-mpc52xx-lite5200-PCI-support.txt ++ features/powerpc/efika/0031-sound-Add-support-for-the-MPC52xx-PSC-AC97-Link.txt ++ features/powerpc/efika/0033-Fix-the-bestcomm-interrupt-property-fixes-the-ethernet-driver.txt