diff options
Diffstat (limited to 'arch/ppc/platforms')
169 files changed, 41379 insertions, 0 deletions
diff --git a/arch/ppc/platforms/4xx/Kconfig b/arch/ppc/platforms/4xx/Kconfig new file mode 100644 index 00000000000..a0612a86455 --- /dev/null +++ b/arch/ppc/platforms/4xx/Kconfig @@ -0,0 +1,247 @@ +config 4xx + bool + depends on 40x || 44x + default y + +menu "IBM 4xx options" + depends on 4xx + +choice + prompt "Machine Type" + depends on 40x + default WALNUT + +config ASH + bool "Ash" + help + This option enables support for the IBM NP405H evaluation board. + +config BUBINGA + bool "Bubinga" + help + This option enables support for the IBM 405EP evaluation board. + +config CPCI405 + bool "CPCI405" + help + This option enables support for the CPCI405 board. + +config EP405 + bool "EP405/EP405PC" + help + This option enables support for the EP405/EP405PC boards. + +config OAK + bool "Oak" + help + This option enables support for the IBM 403GCX evaluation board. + +config REDWOOD_5 + bool "Redwood-5" + help + This option enables support for the IBM STB04 evaluation board. + +config REDWOOD_6 + bool "Redwood-6" + help + This option enables support for the IBM STBx25xx evaluation board. + +config SYCAMORE + bool "Sycamore" + help + This option enables support for the IBM PPC405GPr evaluation board. + +config WALNUT + bool "Walnut" + help + This option enables support for the IBM PPC405GP evaluation board. + +config XILINX_ML300 + bool "Xilinx-ML300" + help + This option enables support for the Xilinx ML300 evaluation board. + +endchoice + +choice + prompt "Machine Type" + depends on 44x + default EBONY + +config EBONY + bool "Ebony" + help + This option enables support for the IBM PPC440GP evaluation board. + +config LUAN + bool "Luan" + help + This option enables support for the IBM PPC440SP evaluation board. + +config OCOTEA + bool "Ocotea" + help + This option enables support for the IBM PPC440GX evaluation board. + +endchoice + +config EP405PC + bool "EP405PC Support" + depends on EP405 + + +# It's often necessary to know the specific 4xx processor type. +# Fortunately, it is impled (so far) from the board type, so we +# don't need to ask more redundant questions. +config NP405H + bool + depends on ASH + default y + +config 440GP + bool + depends on EBONY + default y + +config 440GX + bool + depends on OCOTEA + default y + +config 440SP + bool + depends on LUAN + default y + +config 440 + bool + depends on 440GP || 440SP + default y + +config 440A + bool + depends on 440GX + default y + +# All 405-based cores up until the 405GPR and 405EP have this errata. +config IBM405_ERR77 + bool + depends on 40x && !403GCX && !405GPR + default y + +# All 40x-based cores, up until the 405GPR and 405EP have this errata. +config IBM405_ERR51 + bool + depends on 40x && !405GPR + default y + +config BOOKE + bool + depends on 44x + default y + +config IBM_OCP + bool + depends on ASH || BUBINGA || CPCI405 || EBONY || EP405 || LUAN || OCOTEA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT + default y + +config XILINX_OCP + bool + depends on XILINX_ML300 + default y + +config IBM_EMAC4 + bool + depends on 440GX || 440SP + default y + +config BIOS_FIXUP + bool + depends on BUBINGA || EP405 || SYCAMORE || WALNUT + default y + +config 403GCX + bool + depends OAK + default y + +config 405EP + bool + depends on BUBINGA + default y + +config 405GP + bool + depends on CPCI405 || EP405 || WALNUT + default y + +config 405GPR + bool + depends on SYCAMORE + default y + +config VIRTEX_II_PRO + bool + depends on XILINX_ML300 + default y + +config STB03xxx + bool + depends on REDWOOD_5 || REDWOOD_6 + default y + +config EMBEDDEDBOOT + bool + depends on EP405 || XILINX_ML300 + default y + +config IBM_OPENBIOS + bool + depends on ASH || BUBINGA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT + default y + +config PPC4xx_DMA + bool "PPC4xx DMA controller support" + depends on 4xx + +config PPC4xx_EDMA + bool + depends on !STB03xxx && PPC4xx_DMA + default y + +config PPC_GEN550 + bool + depends on 4xx + default y + +config PM + bool "Power Management support (EXPERIMENTAL)" + depends on 4xx && EXPERIMENTAL + +choice + prompt "TTYS0 device and default console" + depends on 40x + default UART0_TTYS0 + +config UART0_TTYS0 + bool "UART0" + +config UART0_TTYS1 + bool "UART1" + +endchoice + +config SERIAL_SICC + bool "SICC Serial port support" + depends on STB03xxx + +config UART1_DFLT_CONSOLE + bool + depends on SERIAL_SICC && UART0_TTYS1 + default y + +config SERIAL_SICC_CONSOLE + bool + depends on SERIAL_SICC && UART0_TTYS1 + default y +endmenu diff --git a/arch/ppc/platforms/4xx/Makefile b/arch/ppc/platforms/4xx/Makefile new file mode 100644 index 00000000000..ea470c6adbb --- /dev/null +++ b/arch/ppc/platforms/4xx/Makefile @@ -0,0 +1,27 @@ +# +# Makefile for the PowerPC 4xx linux kernel. + +obj-$(CONFIG_ASH) += ash.o +obj-$(CONFIG_CPCI405) += cpci405.o +obj-$(CONFIG_EBONY) += ebony.o +obj-$(CONFIG_EP405) += ep405.o +obj-$(CONFIG_BUBINGA) += bubinga.o +obj-$(CONFIG_LUAN) += luan.o +obj-$(CONFIG_OAK) += oak.o +obj-$(CONFIG_OCOTEA) += ocotea.o +obj-$(CONFIG_REDWOOD_5) += redwood5.o +obj-$(CONFIG_REDWOOD_6) += redwood6.o +obj-$(CONFIG_SYCAMORE) += sycamore.o +obj-$(CONFIG_WALNUT) += walnut.o +obj-$(CONFIG_XILINX_ML300) += xilinx_ml300.o + +obj-$(CONFIG_405GP) += ibm405gp.o +obj-$(CONFIG_REDWOOD_5) += ibmstb4.o +obj-$(CONFIG_NP405H) += ibmnp405h.o +obj-$(CONFIG_REDWOOD_6) += ibmstbx25.o +obj-$(CONFIG_440GP) += ibm440gp.o +obj-$(CONFIG_440GX) += ibm440gx.o +obj-$(CONFIG_440SP) += ibm440sp.o +obj-$(CONFIG_405EP) += ibm405ep.o +obj-$(CONFIG_405GPR) += ibm405gpr.o +obj-$(CONFIG_VIRTEX_II_PRO) += virtex-ii_pro.o diff --git a/arch/ppc/platforms/4xx/ash.c b/arch/ppc/platforms/4xx/ash.c new file mode 100644 index 00000000000..ce291179371 --- /dev/null +++ b/arch/ppc/platforms/4xx/ash.c @@ -0,0 +1,250 @@ +/* + * arch/ppc/platforms/4xx/ash.c + * + * Support for the IBM NP405H ash eval board + * + * Author: Armin Kuster <akuster@mvista.com> + * + * 2001-2002 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/pagemap.h> +#include <linux/pci.h> + +#include <asm/machdep.h> +#include <asm/pci-bridge.h> +#include <asm/io.h> +#include <asm/ocp.h> +#include <asm/ibm_ocp_pci.h> +#include <asm/todc.h> + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +void *ash_rtc_base; + +/* Some IRQs unique to Walnut. + * Used by the generic 405 PCI setup functions in ppc4xx_pci.c + */ +int __init +ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {24, 24, 24, 24}, /* IDSEL 1 - PCI slot 1 */ + {25, 25, 25, 25}, /* IDSEL 2 - PCI slot 2 */ + {26, 26, 26, 26}, /* IDSEL 3 - PCI slot 3 */ + {27, 27, 27, 27}, /* IDSEL 4 - PCI slot 4 */ + }; + + const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +} + +void __init +ash_setup_arch(void) +{ + ppc4xx_setup_arch(); + + ibm_ocp_set_emac(0, 3); + +#ifdef CONFIG_DEBUG_BRINGUP + int i; + printk("\n"); + printk("machine\t: %s\n", PPC4xx_MACHINE_NAME); + printk("\n"); + printk("bi_s_version\t %s\n", bip->bi_s_version); + printk("bi_r_version\t %s\n", bip->bi_r_version); + printk("bi_memsize\t 0x%8.8x\t %dMBytes\n", bip->bi_memsize, + bip->bi_memsize / (1024 * 1000)); + for (i = 0; i < EMAC_NUMS; i++) { + printk("bi_enetaddr %d\t %2.2x%2.2x%2.2x-%2.2x%2.2x%2.2x\n", i, + bip->bi_enetaddr[i][0], bip->bi_enetaddr[i][1], + bip->bi_enetaddr[i][2], bip->bi_enetaddr[i][3], + bip->bi_enetaddr[i][4], bip->bi_enetaddr[i][5]); + } + printk("bi_pci_enetaddr %d\t %2.2x%2.2x%2.2x-%2.2x%2.2x%2.2x\n", 0, + bip->bi_pci_enetaddr[0], bip->bi_pci_enetaddr[1], + bip->bi_pci_enetaddr[2], bip->bi_pci_enetaddr[3], + bip->bi_pci_enetaddr[4], bip->bi_pci_enetaddr[5]); + + printk("bi_intfreq\t 0x%8.8x\t clock:\t %dMhz\n", + bip->bi_intfreq, bip->bi_intfreq / 1000000); + + printk("bi_busfreq\t 0x%8.8x\t plb bus clock:\t %dMHz\n", + bip->bi_busfreq, bip->bi_busfreq / 1000000); + printk("bi_pci_busfreq\t 0x%8.8x\t pci bus clock:\t %dMHz\n", + bip->bi_pci_busfreq, bip->bi_pci_busfreq / 1000000); + + printk("\n"); +#endif + /* RTC step for ash */ + ash_rtc_base = (void *) ASH_RTC_VADDR; + TODC_INIT(TODC_TYPE_DS1743, ash_rtc_base, ash_rtc_base, ash_rtc_base, + 8); +} + +void __init +bios_fixup(struct pci_controller *hose, struct pcil0_regs *pcip) +{ + /* + * Expected PCI mapping: + * + * PLB addr PCI memory addr + * --------------------- --------------------- + * 0000'0000 - 7fff'ffff <--- 0000'0000 - 7fff'ffff + * 8000'0000 - Bfff'ffff ---> 8000'0000 - Bfff'ffff + * + * PLB addr PCI io addr + * --------------------- --------------------- + * e800'0000 - e800'ffff ---> 0000'0000 - 0001'0000 + * + * The following code is simplified by assuming that the bootrom + * has been well behaved in following this mapping. + */ + +#ifdef DEBUG + int i; + + printk("ioremap PCLIO_BASE = 0x%x\n", pcip); + printk("PCI bridge regs before fixup \n"); + for (i = 0; i <= 2; i++) { + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma))); + printk(" pmm%dla\t0x%x\n", i, in_le32(&(pcip->pmm[i].la))); + printk(" pmm%dpcila\t0x%x\n", i, + in_le32(&(pcip->pmm[i].pcila))); + printk(" pmm%dpciha\t0x%x\n", i, + in_le32(&(pcip->pmm[i].pciha))); + } + printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms))); + printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la))); + printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms))); + printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la))); + for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) { + early_read_config_dword(hose, hose->first_busno, + PCI_FUNC(hose->first_busno), bar, + &bar_response); + DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n", + hose->first_busno, PCI_SLOT(hose->first_busno), + PCI_FUNC(hose->first_busno), bar, bar_response); + } + +#endif + if (ppc_md.progress) + ppc_md.progress("bios_fixup(): enter", 0x800); + + /* added for IBM boot rom version 1.15 bios bar changes -AK */ + + /* Disable region first */ + out_le32((void *) &(pcip->pmm[0].ma), 0x00000000); + /* PLB starting addr, PCI: 0x80000000 */ + out_le32((void *) &(pcip->pmm[0].la), 0x80000000); + /* PCI start addr, 0x80000000 */ + out_le32((void *) &(pcip->pmm[0].pcila), PPC405_PCI_MEM_BASE); + /* 512MB range of PLB to PCI */ + out_le32((void *) &(pcip->pmm[0].pciha), 0x00000000); + /* Enable no pre-fetch, enable region */ + out_le32((void *) &(pcip->pmm[0].ma), ((0xffffffff - + (PPC405_PCI_UPPER_MEM - + PPC405_PCI_MEM_BASE)) | 0x01)); + + /* Disable region one */ + out_le32((void *) &(pcip->pmm[1].ma), 0x00000000); + out_le32((void *) &(pcip->pmm[1].la), 0x00000000); + out_le32((void *) &(pcip->pmm[1].pcila), 0x00000000); + out_le32((void *) &(pcip->pmm[1].pciha), 0x00000000); + out_le32((void *) &(pcip->pmm[1].ma), 0x00000000); + + /* Disable region two */ + out_le32((void *) &(pcip->pmm[2].ma), 0x00000000); + out_le32((void *) &(pcip->pmm[2].la), 0x00000000); + out_le32((void *) &(pcip->pmm[2].pcila), 0x00000000); + out_le32((void *) &(pcip->pmm[2].pciha), 0x00000000); + out_le32((void *) &(pcip->pmm[2].ma), 0x00000000); + + /* Enable PTM1 and PTM2, mapped to PLB address 0. */ + + out_le32((void *) &(pcip->ptm1la), 0x00000000); + out_le32((void *) &(pcip->ptm1ms), 0x00000001); + out_le32((void *) &(pcip->ptm2la), 0x00000000); + out_le32((void *) &(pcip->ptm2ms), 0x00000001); + + /* Write zero to PTM1 BAR. */ + + early_write_config_dword(hose, hose->first_busno, + PCI_FUNC(hose->first_busno), + PCI_BASE_ADDRESS_1, + 0x00000000); + + /* Disable PTM2 (unused) */ + + out_le32((void *) &(pcip->ptm2la), 0x00000000); + out_le32((void *) &(pcip->ptm2ms), 0x00000000); + + /* end work arround */ + if (ppc_md.progress) + ppc_md.progress("bios_fixup(): done", 0x800); + +#ifdef DEBUG + printk("PCI bridge regs after fixup \n"); + for (i = 0; i <= 2; i++) { + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma))); + printk(" pmm%dla\t0x%x\n", i, in_le32(&(pcip->pmm[i].la))); + printk(" pmm%dpcila\t0x%x\n", i, + in_le32(&(pcip->pmm[i].pcila))); + printk(" pmm%dpciha\t0x%x\n", i, + in_le32(&(pcip->pmm[i].pciha))); + } + printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms))); + printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la))); + printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms))); + printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la))); + + for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) { + early_read_config_dword(hose, hose->first_busno, + PCI_FUNC(hose->first_busno), bar, + &bar_response); + DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n", + hose->first_busno, PCI_SLOT(hose->first_busno), + PCI_FUNC(hose->first_busno), bar, bar_response); + } + + +#endif +} + +void __init +ash_map_io(void) +{ + ppc4xx_map_io(); + io_block_mapping(ASH_RTC_VADDR, ASH_RTC_PADDR, ASH_RTC_SIZE, _PAGE_IO); +} + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + ppc4xx_init(r3, r4, r5, r6, r7); + + ppc_md.setup_arch = ash_setup_arch; + ppc_md.setup_io_mappings = ash_map_io; + +#ifdef CONFIG_PPC_RTC + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; +#endif +} diff --git a/arch/ppc/platforms/4xx/ash.h b/arch/ppc/platforms/4xx/ash.h new file mode 100644 index 00000000000..5f7448ea418 --- /dev/null +++ b/arch/ppc/platforms/4xx/ash.h @@ -0,0 +1,83 @@ +/* + * arch/ppc/platforms/4xx/ash.h + * + * Macros, definitions, and data structures specific to the IBM PowerPC + * Ash eval board. + * + * Author: Armin Kuster <akuster@mvista.com> + * + * 2000-2002 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_ASH_H__ +#define __ASM_ASH_H__ +#include <platforms/4xx/ibmnp405h.h> + +#ifndef __ASSEMBLY__ +/* + * Data structure defining board information maintained by the boot + * ROM on IBM's "Ash" evaluation board. An effort has been made to + * keep the field names consistent with the 8xx 'bd_t' board info + * structures. + */ + +typedef struct board_info { + unsigned char bi_s_version[4]; /* Version of this structure */ + unsigned char bi_r_version[30]; /* Version of the IBM ROM */ + unsigned int bi_memsize; /* DRAM installed, in bytes */ + unsigned char bi_enetaddr[4][6]; /* Local Ethernet MAC address */ + unsigned char bi_pci_enetaddr[6]; + unsigned int bi_intfreq; /* Processor speed, in Hz */ + unsigned int bi_busfreq; /* PLB Bus speed, in Hz */ + unsigned int bi_pci_busfreq; /* PCI speed in Hz */ +} bd_t; + +/* Some 4xx parts use a different timebase frequency from the internal clock. +*/ +#define bi_tbfreq bi_intfreq + +/* Memory map for the IBM "Ash" NP405H evaluation board. + */ + +extern void *ash_rtc_base; +#define ASH_RTC_PADDR ((uint)0xf0000000) +#define ASH_RTC_VADDR ASH_RTC_PADDR +#define ASH_RTC_SIZE ((uint)8*1024) + + +/* Early initialization address mapping for block_io. + * Standard 405GP map. + */ +#define PPC4xx_PCI_IO_PADDR ((uint)PPC405_PCI_PHY_IO_BASE) +#define PPC4xx_PCI_IO_VADDR PPC4xx_PCI_IO_PADDR +#define PPC4xx_PCI_IO_SIZE ((uint)64*1024) +#define PPC4xx_PCI_CFG_PADDR ((uint)PPC405_PCI_CONFIG_ADDR) +#define PPC4xx_PCI_CFG_VADDR PPC4xx_PCI_CFG_PADDR +#define PPC4xx_PCI_CFG_SIZE ((uint)4*1024) +#define PPC4xx_PCI_LCFG_PADDR ((uint)0xef400000) +#define PPC4xx_PCI_LCFG_VADDR PPC4xx_PCI_LCFG_PADDR +#define PPC4xx_PCI_LCFG_SIZE ((uint)4*1024) +#define PPC4xx_ONB_IO_PADDR ((uint)0xef600000) +#define PPC4xx_ONB_IO_VADDR PPC4xx_ONB_IO_PADDR +#define PPC4xx_ONB_IO_SIZE ((uint)4*1024) + +#define NR_BOARD_IRQS 32 + +#ifdef CONFIG_PPC405GP_INTERNAL_CLOCK +#define BASE_BAUD 201600 +#else +#define BASE_BAUD 691200 +#endif + +#define PPC4xx_MACHINE_NAME "IBM NP405H Ash" + +extern char pci_irq_table[][4]; + + +#endif /* !__ASSEMBLY__ */ +#endif /* __ASM_ASH_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/bubinga.c b/arch/ppc/platforms/4xx/bubinga.c new file mode 100644 index 00000000000..3678abf8631 --- /dev/null +++ b/arch/ppc/platforms/4xx/bubinga.c @@ -0,0 +1,263 @@ +/* + * Support for IBM PPC 405EP evaluation board (Bubinga). + * + * Author: SAW (IBM), derived from walnut.c. + * Maintained by MontaVista Software <source@mvista.com> + * + * 2003 (c) MontaVista Softare Inc. This file is licensed under the + * terms of the GNU General Public License version 2. This program is + * licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/smp.h> +#include <linux/threads.h> +#include <linux/param.h> +#include <linux/string.h> +#include <linux/blkdev.h> +#include <linux/pci.h> +#include <linux/rtc.h> +#include <linux/tty.h> +#include <linux/serial.h> +#include <linux/serial_core.h> + +#include <asm/system.h> +#include <asm/pci-bridge.h> +#include <asm/processor.h> +#include <asm/machdep.h> +#include <asm/page.h> +#include <asm/time.h> +#include <asm/io.h> +#include <asm/todc.h> +#include <asm/kgdb.h> +#include <asm/ocp.h> +#include <asm/ibm_ocp_pci.h> + +#include <platforms/4xx/ibm405ep.h> + +#undef DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +extern bd_t __res; + +void *bubinga_rtc_base; + +/* Some IRQs unique to the board + * Used by the generic 405 PCI setup functions in ppc4xx_pci.c + */ +int __init +ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {28, 28, 28, 28}, /* IDSEL 1 - PCI slot 1 */ + {29, 29, 29, 29}, /* IDSEL 2 - PCI slot 2 */ + {30, 30, 30, 30}, /* IDSEL 3 - PCI slot 3 */ + {31, 31, 31, 31}, /* IDSEL 4 - PCI slot 4 */ + }; + + const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +}; + +/* The serial clock for the chip is an internal clock determined by + * different clock speeds/dividers. + * Calculate the proper input baud rate and setup the serial driver. + */ +static void __init +bubinga_early_serial_map(void) +{ + u32 uart_div; + int uart_clock; + struct uart_port port; + + /* Calculate the serial clock input frequency + * + * The base baud is the PLL OUTA (provided in the board info + * structure) divided by the external UART Divisor, divided + * by 16. + */ + uart_div = (mfdcr(DCRN_CPC0_UCR_BASE) & DCRN_CPC0_UCR_U0DIV); + uart_clock = __res.bi_pllouta_freq / uart_div; + + /* Setup serial port access */ + memset(&port, 0, sizeof(port)); + port.membase = (void*)ACTING_UART0_IO_BASE; + port.irq = ACTING_UART0_INT; + port.uartclk = uart_clock; + port.regshift = 0; + port.iotype = SERIAL_IO_MEM; + port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST; + port.line = 0; + + if (early_serial_setup(&port) != 0) { + printk("Early serial init of port 0 failed\n"); + } + + port.membase = (void*)ACTING_UART1_IO_BASE; + port.irq = ACTING_UART1_INT; + port.line = 1; + + if (early_serial_setup(&port) != 0) { + printk("Early serial init of port 1 failed\n"); + } +} + +void __init +bios_fixup(struct pci_controller *hose, struct pcil0_regs *pcip) +{ + + unsigned int bar_response, bar; + /* + * Expected PCI mapping: + * + * PLB addr PCI memory addr + * --------------------- --------------------- + * 0000'0000 - 7fff'ffff <--- 0000'0000 - 7fff'ffff + * 8000'0000 - Bfff'ffff ---> 8000'0000 - Bfff'ffff + * + * PLB addr PCI io addr + * --------------------- --------------------- + * e800'0000 - e800'ffff ---> 0000'0000 - 0001'0000 + * + * The following code is simplified by assuming that the bootrom + * has been well behaved in following this mapping. + */ + +#ifdef DEBUG + int i; + + printk("ioremap PCLIO_BASE = 0x%x\n", pcip); + printk("PCI bridge regs before fixup \n"); + for (i = 0; i <= 3; i++) { + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma))); + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la))); + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila))); + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha))); + } + printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms))); + printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la))); + printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms))); + printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la))); + +#endif + + /* added for IBM boot rom version 1.15 bios bar changes -AK */ + + /* Disable region first */ + out_le32((void *) &(pcip->pmm[0].ma), 0x00000000); + /* PLB starting addr, PCI: 0x80000000 */ + out_le32((void *) &(pcip->pmm[0].la), 0x80000000); + /* PCI start addr, 0x80000000 */ + out_le32((void *) &(pcip->pmm[0].pcila), PPC405_PCI_MEM_BASE); + /* 512MB range of PLB to PCI */ + out_le32((void *) &(pcip->pmm[0].pciha), 0x00000000); + /* Enable no pre-fetch, enable region */ + out_le32((void *) &(pcip->pmm[0].ma), ((0xffffffff - + (PPC405_PCI_UPPER_MEM - + PPC405_PCI_MEM_BASE)) | 0x01)); + + /* Disable region one */ + out_le32((void *) &(pcip->pmm[1].ma), 0x00000000); + out_le32((void *) &(pcip->pmm[1].la), 0x00000000); + out_le32((void *) &(pcip->pmm[1].pcila), 0x00000000); + out_le32((void *) &(pcip->pmm[1].pciha), 0x00000000); + out_le32((void *) &(pcip->pmm[1].ma), 0x00000000); + out_le32((void *) &(pcip->ptm1ms), 0x00000001); + + /* Disable region two */ + out_le32((void *) &(pcip->pmm[2].ma), 0x00000000); + out_le32((void *) &(pcip->pmm[2].la), 0x00000000); + out_le32((void *) &(pcip->pmm[2].pcila), 0x00000000); + out_le32((void *) &(pcip->pmm[2].pciha), 0x00000000); + out_le32((void *) &(pcip->pmm[2].ma), 0x00000000); + out_le32((void *) &(pcip->ptm2ms), 0x00000000); + out_le32((void *) &(pcip->ptm2la), 0x00000000); + + /* Zero config bars */ + for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) { + early_write_config_dword(hose, hose->first_busno, + PCI_FUNC(hose->first_busno), bar, + 0x00000000); + early_read_config_dword(hose, hose->first_busno, + PCI_FUNC(hose->first_busno), bar, + &bar_response); + DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n", + hose->first_busno, PCI_SLOT(hose->first_busno), + PCI_FUNC(hose->first_busno), bar, bar_response); + } + /* end work arround */ + +#ifdef DEBUG + printk("PCI bridge regs after fixup \n"); + for (i = 0; i <= 3; i++) { + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma))); + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la))); + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila))); + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha))); + } + printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms))); + printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la))); + printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms))); + printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la))); + +#endif +} + +void __init +bubinga_setup_arch(void) +{ + ppc4xx_setup_arch(); + + ibm_ocp_set_emac(0, 1); + + bubinga_early_serial_map(); + + /* RTC step for the evb405ep */ + bubinga_rtc_base = (void *) BUBINGA_RTC_VADDR; + TODC_INIT(TODC_TYPE_DS1743, bubinga_rtc_base, bubinga_rtc_base, + bubinga_rtc_base, 8); + /* Identify the system */ + printk("IBM Bubinga port (MontaVista Software, Inc. <source@mvista.com>)\n"); +} + +void __init +bubinga_map_io(void) +{ + ppc4xx_map_io(); + io_block_mapping(BUBINGA_RTC_VADDR, + BUBINGA_RTC_PADDR, BUBINGA_RTC_SIZE, _PAGE_IO); +} + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + ppc4xx_init(r3, r4, r5, r6, r7); + + ppc_md.setup_arch = bubinga_setup_arch; + ppc_md.setup_io_mappings = bubinga_map_io; + +#ifdef CONFIG_GEN_RTC + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; +#endif +#ifdef CONFIG_KGDB + ppc_md.early_serial_map = bubinga_early_serial_map; +#endif +} + diff --git a/arch/ppc/platforms/4xx/bubinga.h b/arch/ppc/platforms/4xx/bubinga.h new file mode 100644 index 00000000000..b1df856f8e2 --- /dev/null +++ b/arch/ppc/platforms/4xx/bubinga.h @@ -0,0 +1,69 @@ +/* + * Support for IBM PPC 405EP evaluation board (Bubinga). + * + * Author: SAW (IBM), derived from walnut.h. + * Maintained by MontaVista Software <source@mvista.com> + * + * 2003 (c) MontaVista Softare 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. + */ + +#ifdef __KERNEL__ +#ifndef __BUBINGA_H__ +#define __BUBINGA_H__ + +/* 405EP */ +#include <platforms/4xx/ibm405ep.h> + +#ifndef __ASSEMBLY__ +/* + * Data structure defining board information maintained by the boot + * ROM on IBM's evaluation board. An effort has been made to + * keep the field names consistent with the 8xx 'bd_t' board info + * structures. + */ + +typedef struct board_info { + unsigned char bi_s_version[4]; /* Version of this structure */ + unsigned char bi_r_version[30]; /* Version of the IBM ROM */ + unsigned int bi_memsize; /* DRAM installed, in bytes */ + unsigned char bi_enetaddr[2][6]; /* Local Ethernet MAC address */ unsigned char bi_pci_enetaddr[6]; /* PCI Ethernet MAC address */ + unsigned int bi_intfreq; /* Processor speed, in Hz */ + unsigned int bi_busfreq; /* PLB Bus speed, in Hz */ + unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */ + unsigned int bi_opb_busfreq; /* OPB Bus speed, in Hz */ + unsigned int bi_pllouta_freq; /* PLL OUTA speed, in Hz */ +} bd_t; + +/* Some 4xx parts use a different timebase frequency from the internal clock. +*/ +#define bi_tbfreq bi_intfreq + + +/* Memory map for the Bubinga board. + * Generic 4xx plus RTC. + */ + +extern void *bubinga_rtc_base; +#define BUBINGA_RTC_PADDR ((uint)0xf0000000) +#define BUBINGA_RTC_VADDR BUBINGA_RTC_PADDR +#define BUBINGA_RTC_SIZE ((uint)8*1024) + +/* The UART clock is based off an internal clock - + * define BASE_BAUD based on the internal clock and divider(s). + * Since BASE_BAUD must be a constant, we will initialize it + * using clock/divider values which OpenBIOS initializes + * for typical configurations at various CPU speeds. + * The base baud is calculated as (FWDA / EXT UART DIV / 16) + */ +#define BASE_BAUD 0 + +#define BUBINGA_FPGA_BASE 0xF0300000 + +#define PPC4xx_MACHINE_NAME "IBM Bubinga" + +#endif /* !__ASSEMBLY__ */ +#endif /* __BUBINGA_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/cpci405.c b/arch/ppc/platforms/4xx/cpci405.c new file mode 100644 index 00000000000..ff966773a0b --- /dev/null +++ b/arch/ppc/platforms/4xx/cpci405.c @@ -0,0 +1,84 @@ +/* + * arch/ppc/platforms/cpci405.c + * + * Board setup routines for the esd CPCI-405 cPCI Board. + * + * Author: Stefan Roese + * stefan.roese@esd-electronics.com + * + * Copyright 2001 esd electronic system design - hannover germany + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <asm/system.h> +#include <asm/pci-bridge.h> +#include <asm/machdep.h> +#include <asm/todc.h> +#include <asm/ocp.h> + +void *cpci405_nvram; + +/* + * Some IRQs unique to CPCI-405. + */ +int __init +ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {28, 28, 28, 28}, /* IDSEL 15 - cPCI slot 8 */ + {29, 29, 29, 29}, /* IDSEL 16 - cPCI slot 7 */ + {30, 30, 30, 30}, /* IDSEL 17 - cPCI slot 6 */ + {27, 27, 27, 27}, /* IDSEL 18 - cPCI slot 5 */ + {28, 28, 28, 28}, /* IDSEL 19 - cPCI slot 4 */ + {29, 29, 29, 29}, /* IDSEL 20 - cPCI slot 3 */ + {30, 30, 30, 30}, /* IDSEL 21 - cPCI slot 2 */ + }; + const long min_idsel = 15, max_idsel = 21, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +}; + +void __init +cpci405_setup_arch(void) +{ + ppc4xx_setup_arch(); + + ibm_ocp_set_emac(0, 0); + + TODC_INIT(TODC_TYPE_MK48T35, cpci405_nvram, cpci405_nvram, cpci405_nvram, 8); +} + +void __init +cpci405_map_io(void) +{ + ppc4xx_map_io(); + cpci405_nvram = ioremap(CPCI405_NVRAM_PADDR, CPCI405_NVRAM_SIZE); +} + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + ppc4xx_init(r3, r4, r5, r6, r7); + + ppc_md.setup_arch = cpci405_setup_arch; + ppc_md.setup_io_mappings = cpci405_map_io; + + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; +} diff --git a/arch/ppc/platforms/4xx/cpci405.h b/arch/ppc/platforms/4xx/cpci405.h new file mode 100644 index 00000000000..e27f7cb650d --- /dev/null +++ b/arch/ppc/platforms/4xx/cpci405.h @@ -0,0 +1,37 @@ +/* + * CPCI-405 board specific definitions + * + * Copyright (c) 2001 Stefan Roese (stefan.roese@esd-electronics.com) + */ + +#ifdef __KERNEL__ +#ifndef __ASM_CPCI405_H__ +#define __ASM_CPCI405_H__ + +#include <linux/config.h> + +/* We have a 405GP core */ +#include <platforms/4xx/ibm405gp.h> + +#include <asm/ppcboot.h> + +#ifndef __ASSEMBLY__ +/* Some 4xx parts use a different timebase frequency from the internal clock. +*/ +#define bi_tbfreq bi_intfreq + +/* Map for the NVRAM space */ +#define CPCI405_NVRAM_PADDR ((uint)0xf0200000) +#define CPCI405_NVRAM_SIZE ((uint)32*1024) + +#ifdef CONFIG_PPC405GP_INTERNAL_CLOCK +#define BASE_BAUD 201600 +#else +#define BASE_BAUD 691200 +#endif + +#define PPC4xx_MACHINE_NAME "esd CPCI-405" + +#endif /* !__ASSEMBLY__ */ +#endif /* __ASM_CPCI405_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/ebony.c b/arch/ppc/platforms/4xx/ebony.c new file mode 100644 index 00000000000..f63bca83e75 --- /dev/null +++ b/arch/ppc/platforms/4xx/ebony.c @@ -0,0 +1,356 @@ +/* + * arch/ppc/platforms/4xx/ebony.c + * + * Ebony board specific routines + * + * Matt Porter <mporter@kernel.crashing.org> + * Copyright 2002-2005 MontaVista Software Inc. + * + * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> + * Copyright (c) 2003, 2004 Zultys Technologies + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/types.h> +#include <linux/major.h> +#include <linux/blkdev.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/ide.h> +#include <linux/initrd.h> +#include <linux/irq.h> +#include <linux/seq_file.h> +#include <linux/root_dev.h> +#include <linux/tty.h> +#include <linux/serial.h> +#include <linux/serial_core.h> + +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/machdep.h> +#include <asm/ocp.h> +#include <asm/pci-bridge.h> +#include <asm/time.h> +#include <asm/todc.h> +#include <asm/bootinfo.h> +#include <asm/ppc4xx_pic.h> +#include <asm/ppcboot.h> + +#include <syslib/gen550.h> +#include <syslib/ibm440gp_common.h> + +/* + * This is a horrible kludge, we eventually need to abstract this + * generic PHY stuff, so the standard phy mode defines can be + * easily used from arch code. + */ +#include "../../../../drivers/net/ibm_emac/ibm_emac_phy.h" + +bd_t __res; + +static struct ibm44x_clocks clocks __initdata; + +/* + * Ebony external IRQ triggering/polarity settings + */ +unsigned char ppc4xx_uic_ext_irq_cfg[] __initdata = { + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ0: PCI slot 0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ1: PCI slot 1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ2: PCI slot 2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ3: PCI slot 3 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ4: IRDA */ + (IRQ_SENSE_EDGE | IRQ_POLARITY_NEGATIVE), /* IRQ5: SMI pushbutton */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ6: PHYs */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ7: AUX */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ8: EXT */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ9: EXT */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ10: EXT */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ11: EXT */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ12: EXT */ +}; + +static void __init +ebony_calibrate_decr(void) +{ + unsigned int freq; + + /* + * Determine system clock speed + * + * If we are on Rev. B silicon, then use + * default external system clock. If we are + * on Rev. C silicon then errata forces us to + * use the internal clock. + */ + switch (PVR_REV(mfspr(SPRN_PVR))) { + case PVR_REV(PVR_440GP_RB): + freq = EBONY_440GP_RB_SYSCLK; + break; + case PVR_REV(PVR_440GP_RC1): + default: + freq = EBONY_440GP_RC_SYSCLK; + break; + } + + ibm44x_calibrate_decr(freq); +} + +static int +ebony_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "vendor\t\t: IBM\n"); + seq_printf(m, "machine\t\t: Ebony\n"); + + return 0; +} + +static inline int +ebony_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + { 23, 23, 23, 23 }, /* IDSEL 1 - PCI Slot 0 */ + { 24, 24, 24, 24 }, /* IDSEL 2 - PCI Slot 1 */ + { 25, 25, 25, 25 }, /* IDSEL 3 - PCI Slot 2 */ + { 26, 26, 26, 26 }, /* IDSEL 4 - PCI Slot 3 */ + }; + + const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +} + +#define PCIX_WRITEL(value, offset) \ + (writel(value, pcix_reg_base + offset)) + +/* + * FIXME: This is only here to "make it work". This will move + * to a ibm_pcix.c which will contain a generic IBM PCIX bridge + * configuration library. -Matt + */ +static void __init +ebony_setup_pcix(void) +{ + void *pcix_reg_base; + + pcix_reg_base = ioremap64(PCIX0_REG_BASE, PCIX_REG_SIZE); + + /* Disable all windows */ + PCIX_WRITEL(0, PCIX0_POM0SA); + PCIX_WRITEL(0, PCIX0_POM1SA); + PCIX_WRITEL(0, PCIX0_POM2SA); + PCIX_WRITEL(0, PCIX0_PIM0SA); + PCIX_WRITEL(0, PCIX0_PIM1SA); + PCIX_WRITEL(0, PCIX0_PIM2SA); + + /* Setup 2GB PLB->PCI outbound mem window (3_8000_0000->0_8000_0000) */ + PCIX_WRITEL(0x00000003, PCIX0_POM0LAH); + PCIX_WRITEL(0x80000000, PCIX0_POM0LAL); + PCIX_WRITEL(0x00000000, PCIX0_POM0PCIAH); + PCIX_WRITEL(0x80000000, PCIX0_POM0PCIAL); + PCIX_WRITEL(0x80000001, PCIX0_POM0SA); + + /* Setup 2GB PCI->PLB inbound memory window at 0, enable MSIs */ + PCIX_WRITEL(0x00000000, PCIX0_PIM0LAH); + PCIX_WRITEL(0x00000000, PCIX0_PIM0LAL); + PCIX_WRITEL(0x80000007, PCIX0_PIM0SA); + + eieio(); +} + +static void __init +ebony_setup_hose(void) +{ + struct pci_controller *hose; + + /* Configure windows on the PCI-X host bridge */ + ebony_setup_pcix(); + + hose = pcibios_alloc_controller(); + + if (!hose) + return; + + hose->first_busno = 0; + hose->last_busno = 0xff; + + hose->pci_mem_offset = EBONY_PCI_MEM_OFFSET; + + pci_init_resource(&hose->io_resource, + EBONY_PCI_LOWER_IO, + EBONY_PCI_UPPER_IO, + IORESOURCE_IO, + "PCI host bridge"); + + pci_init_resource(&hose->mem_resources[0], + EBONY_PCI_LOWER_MEM, + EBONY_PCI_UPPER_MEM, + IORESOURCE_MEM, + "PCI host bridge"); + + hose->io_space.start = EBONY_PCI_LOWER_IO; + hose->io_space.end = EBONY_PCI_UPPER_IO; + hose->mem_space.start = EBONY_PCI_LOWER_MEM; + hose->mem_space.end = EBONY_PCI_UPPER_MEM; + isa_io_base = + (unsigned long)ioremap64(EBONY_PCI_IO_BASE, EBONY_PCI_IO_SIZE); + hose->io_base_virt = (void *)isa_io_base; + + setup_indirect_pci(hose, + EBONY_PCI_CFGA_PLB32, + EBONY_PCI_CFGD_PLB32); + hose->set_cfg_type = 1; + + hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); + + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = ebony_map_irq; +} + +TODC_ALLOC(); + +static void __init +ebony_early_serial_map(void) +{ + struct uart_port port; + + /* Setup ioremapped serial port access */ + memset(&port, 0, sizeof(port)); + port.membase = ioremap64(PPC440GP_UART0_ADDR, 8); + port.irq = 0; + port.uartclk = clocks.uart0; + port.regshift = 0; + port.iotype = SERIAL_IO_MEM; + port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST; + port.line = 0; + + if (early_serial_setup(&port) != 0) { + printk("Early serial init of port 0 failed\n"); + } + +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) + /* Configure debug serial access */ + gen550_init(0, &port); +#endif + + port.membase = ioremap64(PPC440GP_UART1_ADDR, 8); + port.irq = 1; + port.uartclk = clocks.uart1; + port.line = 1; + + if (early_serial_setup(&port) != 0) { + printk("Early serial init of port 1 failed\n"); + } + +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) + /* Configure debug serial access */ + gen550_init(1, &port); +#endif +} + +static void __init +ebony_setup_arch(void) +{ + struct ocp_def *def; + struct ocp_func_emac_data *emacdata; + + /* Set mac_addr for each EMAC */ + def = ocp_get_one_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, 0); + emacdata = def->additions; + emacdata->phy_map = 0x00000001; /* Skip 0x00 */ + emacdata->phy_mode = PHY_MODE_RMII; + memcpy(emacdata->mac_addr, __res.bi_enetaddr, 6); + + def = ocp_get_one_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, 1); + emacdata = def->additions; + emacdata->phy_map = 0x00000001; /* Skip 0x00 */ + emacdata->phy_mode = PHY_MODE_RMII; + memcpy(emacdata->mac_addr, __res.bi_enet1addr, 6); + + /* + * Determine various clocks. + * To be completely correct we should get SysClk + * from FPGA, because it can be changed by on-board switches + * --ebs + */ + ibm440gp_get_clocks(&clocks, 33333333, 6 * 1843200); + ocp_sys_info.opb_bus_freq = clocks.opb; + + /* Setup TODC access */ + TODC_INIT(TODC_TYPE_DS1743, + 0, + 0, + ioremap64(EBONY_RTC_ADDR, EBONY_RTC_SIZE), + 8); + + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000/HZ; + + /* Setup PCI host bridge */ + ebony_setup_hose(); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_HDA1; +#endif + + ebony_early_serial_map(); + + /* Identify the system */ + printk("IBM Ebony port (MontaVista Software, Inc. (source@mvista.com))\n"); +} + +void __init platform_init(unsigned long r3, unsigned long r4, + unsigned long r5, unsigned long r6, unsigned long r7) +{ + parse_bootinfo(find_bootinfo()); + + /* + * If we were passed in a board information, copy it into the + * residual data area. + */ + if (r3) + __res = *(bd_t *)(r3 + KERNELBASE); + + ibm44x_platform_init(); + + ppc_md.setup_arch = ebony_setup_arch; + ppc_md.show_cpuinfo = ebony_show_cpuinfo; + ppc_md.get_irq = NULL; /* Set in ppc4xx_pic_init() */ + + ppc_md.calibrate_decr = ebony_calibrate_decr; + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; +#ifdef CONFIG_KGDB + ppc_md.early_serial_map = ebony_early_serial_map; +#endif +} + diff --git a/arch/ppc/platforms/4xx/ebony.h b/arch/ppc/platforms/4xx/ebony.h new file mode 100644 index 00000000000..47c391c9174 --- /dev/null +++ b/arch/ppc/platforms/4xx/ebony.h @@ -0,0 +1,91 @@ +/* + * arch/ppc/platforms/ebony.h + * + * Ebony board definitions + * + * Matt Porter <mporter@mvista.com> + * + * Copyright 2002 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_EBONY_H__ +#define __ASM_EBONY_H__ + +#include <linux/config.h> +#include <platforms/4xx/ibm440gp.h> + +/* F/W TLB mapping used in bootloader glue to reset EMAC */ +#define PPC44x_EMAC0_MR0 0xE0000800 + +/* Where to find the MAC info */ +#define EBONY_OPENBIOS_MAC_BASE 0xfffffe0c +#define EBONY_OPENBIOS_MAC_OFFSET 0x0c + +/* Default clock rates for Rev. B and Rev. C silicon */ +#define EBONY_440GP_RB_SYSCLK 33000000 +#define EBONY_440GP_RC_SYSCLK 400000000 + +/* RTC/NVRAM location */ +#define EBONY_RTC_ADDR 0x0000000148000000ULL +#define EBONY_RTC_SIZE 0x2000 + +/* Flash */ +#define EBONY_FPGA_ADDR 0x0000000148300000ULL +#define EBONY_BOOT_SMALL_FLASH(x) (x & 0x20) +#define EBONY_ONBRD_FLASH_EN(x) (x & 0x02) +#define EBONY_FLASH_SEL(x) (x & 0x01) +#define EBONY_SMALL_FLASH_LOW1 0x00000001ff800000ULL +#define EBONY_SMALL_FLASH_LOW2 0x00000001ff880000ULL +#define EBONY_SMALL_FLASH_HIGH1 0x00000001fff00000ULL +#define EBONY_SMALL_FLASH_HIGH2 0x00000001fff80000ULL +#define EBONY_SMALL_FLASH_SIZE 0x80000 +#define EBONY_LARGE_FLASH_LOW 0x00000001ff800000ULL +#define EBONY_LARGE_FLASH_HIGH 0x00000001ffc00000ULL +#define EBONY_LARGE_FLASH_SIZE 0x400000 + +#define EBONY_SMALL_FLASH_BASE 0x00000001fff80000ULL +#define EBONY_LARGE_FLASH_BASE 0x00000001ff800000ULL + +/* + * Serial port defines + */ + +/* OpenBIOS defined UART mappings, used before early_serial_setup */ +#define UART0_IO_BASE 0xE0000200 +#define UART1_IO_BASE 0xE0000300 + +/* external Epson SG-615P */ +#define BASE_BAUD 691200 + +#define STD_UART_OP(num) \ + { 0, BASE_BAUD, 0, UART##num##_INT, \ + (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \ + iomem_base: UART##num##_IO_BASE, \ + io_type: SERIAL_IO_MEM}, + +#define SERIAL_PORT_DFNS \ + STD_UART_OP(0) \ + STD_UART_OP(1) + +/* PCI support */ +#define EBONY_PCI_LOWER_IO 0x00000000 +#define EBONY_PCI_UPPER_IO 0x0000ffff +#define EBONY_PCI_LOWER_MEM 0x80002000 +#define EBONY_PCI_UPPER_MEM 0xffffefff + +#define EBONY_PCI_CFGREGS_BASE 0x000000020ec00000 +#define EBONY_PCI_CFGA_PLB32 0x0ec00000 +#define EBONY_PCI_CFGD_PLB32 0x0ec00004 + +#define EBONY_PCI_IO_BASE 0x0000000208000000ULL +#define EBONY_PCI_IO_SIZE 0x00010000 +#define EBONY_PCI_MEM_OFFSET 0x00000000 + +#endif /* __ASM_EBONY_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/ep405.c b/arch/ppc/platforms/4xx/ep405.c new file mode 100644 index 00000000000..26a07cdb30e --- /dev/null +++ b/arch/ppc/platforms/4xx/ep405.c @@ -0,0 +1,197 @@ +/* + * arch/ppc/platforms/4xx/ep405.c + * + * Embedded Planet 405GP board + * http://www.embeddedplanet.com + * + * Author: Matthew Locke <mlocke@mvista.com> + * + * 2001 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <asm/system.h> +#include <asm/pci-bridge.h> +#include <asm/machdep.h> +#include <asm/todc.h> +#include <asm/ocp.h> +#include <asm/ibm_ocp_pci.h> + +#undef DEBUG +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +u8 *ep405_bcsr; +u8 *ep405_nvram; + +static struct { + u8 cpld_xirq_select; + int pci_idsel; + int irq; +} ep405_devtable[] = { +#ifdef CONFIG_EP405PC + {0x07, 0x0E, 25}, /* EP405PC: USB */ +#endif +}; + +int __init +ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + int i; + + /* AFAICT this is only called a few times during PCI setup, so + performance is not critical */ + for (i = 0; i < ARRAY_SIZE(ep405_devtable); i++) { + if (idsel == ep405_devtable[i].pci_idsel) + return ep405_devtable[i].irq; + } + return -1; +}; + +void __init +ep405_setup_arch(void) +{ + ppc4xx_setup_arch(); + + ibm_ocp_set_emac(0, 0); + + if (__res.bi_nvramsize == 512*1024) { + /* FIXME: we should properly handle NVRTCs of different sizes */ + TODC_INIT(TODC_TYPE_DS1557, ep405_nvram, ep405_nvram, ep405_nvram, 8); + } +} + +void __init +bios_fixup(struct pci_controller *hose, struct pcil0_regs *pcip) +{ + unsigned int bar_response, bar; + /* + * Expected PCI mapping: + * + * PLB addr PCI memory addr + * --------------------- --------------------- + * 0000'0000 - 7fff'ffff <--- 0000'0000 - 7fff'ffff + * 8000'0000 - Bfff'ffff ---> 8000'0000 - Bfff'ffff + * + * PLB addr PCI io addr + * --------------------- --------------------- + * e800'0000 - e800'ffff ---> 0000'0000 - 0001'0000 + * + */ + + /* Disable region zero first */ + out_le32((void *) &(pcip->pmm[0].ma), 0x00000000); + /* PLB starting addr, PCI: 0x80000000 */ + out_le32((void *) &(pcip->pmm[0].la), 0x80000000); + /* PCI start addr, 0x80000000 */ + out_le32((void *) &(pcip->pmm[0].pcila), PPC405_PCI_MEM_BASE); + /* 512MB range of PLB to PCI */ + out_le32((void *) &(pcip->pmm[0].pciha), 0x00000000); + /* Enable no pre-fetch, enable region */ + out_le32((void *) &(pcip->pmm[0].ma), ((0xffffffff - + (PPC405_PCI_UPPER_MEM - + PPC405_PCI_MEM_BASE)) | 0x01)); + + /* Disable region one */ + out_le32((void *) &(pcip->pmm[1].ma), 0x00000000); + out_le32((void *) &(pcip->pmm[1].la), 0x00000000); + out_le32((void *) &(pcip->pmm[1].pcila), 0x00000000); + out_le32((void *) &(pcip->pmm[1].pciha), 0x00000000); + out_le32((void *) &(pcip->pmm[1].ma), 0x00000000); + out_le32((void *) &(pcip->ptm1ms), 0x00000000); + + /* Disable region two */ + out_le32((void *) &(pcip->pmm[2].ma), 0x00000000); + out_le32((void *) &(pcip->pmm[2].la), 0x00000000); + out_le32((void *) &(pcip->pmm[2].pcila), 0x00000000); + out_le32((void *) &(pcip->pmm[2].pciha), 0x00000000); + out_le32((void *) &(pcip->pmm[2].ma), 0x00000000); + out_le32((void *) &(pcip->ptm2ms), 0x00000000); + + /* Configure PTM (PCI->PLB) region 1 */ + out_le32((void *) &(pcip->ptm1la), 0x00000000); /* PLB base address */ + /* Disable PTM region 2 */ + out_le32((void *) &(pcip->ptm2ms), 0x00000000); + + /* Zero config bars */ + for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) { + early_write_config_dword(hose, hose->first_busno, + PCI_FUNC(hose->first_busno), bar, + 0x00000000); + early_read_config_dword(hose, hose->first_busno, + PCI_FUNC(hose->first_busno), bar, + &bar_response); + DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n", + hose->first_busno, PCI_SLOT(hose->first_busno), + PCI_FUNC(hose->first_busno), bar, bar_response); + } + /* end work arround */ +} + +void __init +ep405_map_io(void) +{ + bd_t *bip = &__res; + + ppc4xx_map_io(); + + ep405_bcsr = ioremap(EP405_BCSR_PADDR, EP405_BCSR_SIZE); + + if (bip->bi_nvramsize > 0) { + ep405_nvram = ioremap(EP405_NVRAM_PADDR, bip->bi_nvramsize); + } +} + +void __init +ep405_init_IRQ(void) +{ + int i; + + ppc4xx_init_IRQ(); + + /* Workaround for a bug in the firmware it incorrectly sets + the IRQ polarities for XIRQ0 and XIRQ1 */ + mtdcr(DCRN_UIC_PR(DCRN_UIC0_BASE), 0xffffff80); /* set the polarity */ + mtdcr(DCRN_UIC_SR(DCRN_UIC0_BASE), 0x00000060); /* clear bogus interrupts */ + + /* Activate the XIRQs from the CPLD */ + writeb(0xf0, ep405_bcsr+10); + + /* Set up IRQ routing */ + for (i = 0; i < ARRAY_SIZE(ep405_devtable); i++) { + if ( (ep405_devtable[i].irq >= 25) + && (ep405_devtable[i].irq) <= 31) { + writeb(ep405_devtable[i].cpld_xirq_select, ep405_bcsr+5); + writeb(ep405_devtable[i].irq - 25, ep405_bcsr+6); + } + } +} + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + ppc4xx_init(r3, r4, r5, r6, r7); + + ppc_md.setup_arch = ep405_setup_arch; + ppc_md.setup_io_mappings = ep405_map_io; + ppc_md.init_IRQ = ep405_init_IRQ; + + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; + + if (__res.bi_nvramsize == 512*1024) { + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + } else { + printk("EP405: NVRTC size is not 512k (not a DS1557). Not sure what to do with it\n"); + } +} diff --git a/arch/ppc/platforms/4xx/ep405.h b/arch/ppc/platforms/4xx/ep405.h new file mode 100644 index 00000000000..ea3eb21338f --- /dev/null +++ b/arch/ppc/platforms/4xx/ep405.h @@ -0,0 +1,54 @@ +/* + * arch/ppc/platforms/4xx/ep405.h + * + * Embedded Planet 405GP board + * http://www.embeddedplanet.com + * + * Author: Matthew Locke <mlocke@mvista.com> + * + * 2000 (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. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_EP405_H__ +#define __ASM_EP405_H__ + +/* We have a 405GP core */ +#include <platforms/4xx/ibm405gp.h> + +#ifndef __ASSEMBLY__ + +#include <linux/types.h> + +typedef struct board_info { + unsigned int bi_memsize; /* DRAM installed, in bytes */ + unsigned char bi_enetaddr[6]; /* Local Ethernet MAC address */ + unsigned int bi_intfreq; /* Processor speed, in Hz */ + unsigned int bi_busfreq; /* PLB Bus speed, in Hz */ + unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */ + unsigned int bi_nvramsize; /* Size of the NVRAM/RTC */ +} bd_t; + +/* Some 4xx parts use a different timebase frequency from the internal clock. +*/ +#define bi_tbfreq bi_intfreq + +extern u8 *ep405_bcsr; +extern u8 *ep405_nvram; + +/* Map for the BCSR and NVRAM space */ +#define EP405_BCSR_PADDR ((uint)0xf4000000) +#define EP405_BCSR_SIZE ((uint)16) +#define EP405_NVRAM_PADDR ((uint)0xf4200000) + +/* serial defines */ +#define BASE_BAUD 399193 + +#define PPC4xx_MACHINE_NAME "Embedded Planet 405GP" + +#endif /* !__ASSEMBLY__ */ +#endif /* __ASM_EP405_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/ibm405ep.c b/arch/ppc/platforms/4xx/ibm405ep.c new file mode 100644 index 00000000000..6d44567f4dd --- /dev/null +++ b/arch/ppc/platforms/4xx/ibm405ep.c @@ -0,0 +1,143 @@ +/* + * arch/ppc/platforms/ibm405ep.c + * + * Support for IBM PPC 405EP processors. + * + * Author: SAW (IBM), derived from ibmnp405l.c. + * Maintained by MontaVista Software <source@mvista.com> + * + * 2003 (c) MontaVista Softare Inc. This file is licensed under the + * terms of the GNU General Public License version 2. This program is + * licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/smp.h> +#include <linux/threads.h> +#include <linux/param.h> +#include <linux/string.h> + +#include <asm/ibm4xx.h> +#include <asm/ocp.h> +#include <asm/ppc4xx_pic.h> + +#include <platforms/4xx/ibm405ep.h> + +static struct ocp_func_mal_data ibm405ep_mal0_def = { + .num_tx_chans = 4, /* Number of TX channels */ + .num_rx_chans = 2, /* Number of RX channels */ + .txeob_irq = 11, /* TX End Of Buffer IRQ */ + .rxeob_irq = 12, /* RX End Of Buffer IRQ */ + .txde_irq = 13, /* TX Descriptor Error IRQ */ + .rxde_irq = 14, /* RX Descriptor Error IRQ */ + .serr_irq = 10, /* MAL System Error IRQ */ +}; +OCP_SYSFS_MAL_DATA() + +static struct ocp_func_emac_data ibm405ep_emac0_def = { + .rgmii_idx = -1, /* No RGMII */ + .rgmii_mux = -1, /* No RGMII */ + .zmii_idx = -1, /* ZMII device index */ + .zmii_mux = 0, /* ZMII input of this EMAC */ + .mal_idx = 0, /* MAL device index */ + .mal_rx_chan = 0, /* MAL rx channel number */ + .mal_tx_chan = 0, /* MAL tx channel number */ + .wol_irq = 9, /* WOL interrupt number */ + .mdio_idx = 0, /* MDIO via EMAC0 */ + .tah_idx = -1, /* No TAH */ +}; + +static struct ocp_func_emac_data ibm405ep_emac1_def = { + .rgmii_idx = -1, /* No RGMII */ + .rgmii_mux = -1, /* No RGMII */ + .zmii_idx = -1, /* ZMII device index */ + .zmii_mux = 0, /* ZMII input of this EMAC */ + .mal_idx = 0, /* MAL device index */ + .mal_rx_chan = 1, /* MAL rx channel number */ + .mal_tx_chan = 2, /* MAL tx channel number */ + .wol_irq = 9, /* WOL interrupt number */ + .mdio_idx = 0, /* MDIO via EMAC0 */ + .tah_idx = -1, /* No TAH */ +}; +OCP_SYSFS_EMAC_DATA() + +static struct ocp_func_iic_data ibm405ep_iic0_def = { + .fast_mode = 0, /* Use standad mode (100Khz) */ +}; +OCP_SYSFS_IIC_DATA() + +struct ocp_def core_ocp[] = { + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_OPB, + .index = 0, + .paddr = 0xEF600000, + .irq = OCP_IRQ_NA, + .pm = OCP_CPM_NA, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 0, + .paddr = UART0_IO_BASE, + .irq = UART0_INT, + .pm = IBM_CPM_UART0 + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 1, + .paddr = UART1_IO_BASE, + .irq = UART1_INT, + .pm = IBM_CPM_UART1 + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_IIC, + .paddr = 0xEF600500, + .irq = 2, + .pm = IBM_CPM_IIC0, + .additions = &ibm405ep_iic0_def, + .show = &ocp_show_iic_data + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_GPIO, + .paddr = 0xEF600700, + .irq = OCP_IRQ_NA, + .pm = IBM_CPM_GPIO0 + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_MAL, + .paddr = OCP_PADDR_NA, + .irq = OCP_IRQ_NA, + .pm = OCP_CPM_NA, + .additions = &ibm405ep_mal0_def, + .show = &ocp_show_mal_data + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_EMAC, + .index = 0, + .paddr = EMAC0_BASE, + .irq = 15, + .pm = OCP_CPM_NA, + .additions = &ibm405ep_emac0_def, + .show = &ocp_show_emac_data + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_EMAC, + .index = 1, + .paddr = 0xEF600900, + .irq = 17, + .pm = OCP_CPM_NA, + .additions = &ibm405ep_emac1_def, + .show = &ocp_show_emac_data + }, + { .vendor = OCP_VENDOR_INVALID + } +}; + +/* Polarity and triggering settings for internal interrupt sources */ +struct ppc4xx_uic_settings ppc4xx_core_uic_cfg[] __initdata = { + { .polarity = 0xffff7f80, + .triggering = 0x00000000, + .ext_irq_mask = 0x0000007f, /* IRQ0 - IRQ6 */ + } +}; diff --git a/arch/ppc/platforms/4xx/ibm405ep.h b/arch/ppc/platforms/4xx/ibm405ep.h new file mode 100644 index 00000000000..e051e3fe8c6 --- /dev/null +++ b/arch/ppc/platforms/4xx/ibm405ep.h @@ -0,0 +1,148 @@ +/* + * arch/ppc/platforms/4xx/ibm405ep.h + * + * IBM PPC 405EP processor defines. + * + * Author: SAW (IBM), derived from ibm405gp.h. + * Maintained by MontaVista Software <source@mvista.com> + * + * 2003 (c) MontaVista Softare 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. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_IBM405EP_H__ +#define __ASM_IBM405EP_H__ + +#include <linux/config.h> + +/* ibm405.h at bottom of this file */ + +/* PCI + * PCI Bridge config reg definitions + * see 17-19 of manual + */ + +#define PPC405_PCI_CONFIG_ADDR 0xeec00000 +#define PPC405_PCI_CONFIG_DATA 0xeec00004 + +#define PPC405_PCI_PHY_MEM_BASE 0x80000000 /* hose_a->pci_mem_offset */ + /* setbat */ +#define PPC405_PCI_MEM_BASE PPC405_PCI_PHY_MEM_BASE /* setbat */ +#define PPC405_PCI_PHY_IO_BASE 0xe8000000 /* setbat */ +#define PPC405_PCI_IO_BASE PPC405_PCI_PHY_IO_BASE /* setbat */ + +#define PPC405_PCI_LOWER_MEM 0x80000000 /* hose_a->mem_space.start */ +#define PPC405_PCI_UPPER_MEM 0xBfffffff /* hose_a->mem_space.end */ +#define PPC405_PCI_LOWER_IO 0x00000000 /* hose_a->io_space.start */ +#define PPC405_PCI_UPPER_IO 0x0000ffff /* hose_a->io_space.end */ + +#define PPC405_ISA_IO_BASE PPC405_PCI_IO_BASE + +#define PPC4xx_PCI_IO_PADDR ((uint)PPC405_PCI_PHY_IO_BASE) +#define PPC4xx_PCI_IO_VADDR PPC4xx_PCI_IO_PADDR +#define PPC4xx_PCI_IO_SIZE ((uint)64*1024) +#define PPC4xx_PCI_CFG_PADDR ((uint)PPC405_PCI_CONFIG_ADDR) +#define PPC4xx_PCI_CFG_VADDR PPC4xx_PCI_CFG_PADDR +#define PPC4xx_PCI_CFG_SIZE ((uint)4*1024) +#define PPC4xx_PCI_LCFG_PADDR ((uint)0xef400000) +#define PPC4xx_PCI_LCFG_VADDR PPC4xx_PCI_LCFG_PADDR +#define PPC4xx_PCI_LCFG_SIZE ((uint)4*1024) +#define PPC4xx_ONB_IO_PADDR ((uint)0xef600000) +#define PPC4xx_ONB_IO_VADDR PPC4xx_ONB_IO_PADDR +#define PPC4xx_ONB_IO_SIZE ((uint)4*1024) + +/* serial port defines */ +#define RS_TABLE_SIZE 2 + +#define UART0_INT 0 +#define UART1_INT 1 + +#define PCIL0_BASE 0xEF400000 +#define UART0_IO_BASE 0xEF600300 +#define UART1_IO_BASE 0xEF600400 +#define EMAC0_BASE 0xEF600800 + +#define BD_EMAC_ADDR(e,i) bi_enetaddr[e][i] + +#if defined(CONFIG_UART0_TTYS0) +#define ACTING_UART0_IO_BASE UART0_IO_BASE +#define ACTING_UART1_IO_BASE UART1_IO_BASE +#define ACTING_UART0_INT UART0_INT +#define ACTING_UART1_INT UART1_INT +#else +#define ACTING_UART0_IO_BASE UART1_IO_BASE +#define ACTING_UART1_IO_BASE UART0_IO_BASE +#define ACTING_UART0_INT UART1_INT +#define ACTING_UART1_INT UART0_INT +#endif + +#define STD_UART_OP(num) \ + { 0, BASE_BAUD, 0, ACTING_UART##num##_INT, \ + (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \ + iomem_base: (u8 *)ACTING_UART##num##_IO_BASE, \ + io_type: SERIAL_IO_MEM}, + +#define SERIAL_DEBUG_IO_BASE ACTING_UART0_IO_BASE +#define SERIAL_PORT_DFNS \ + STD_UART_OP(0) \ + STD_UART_OP(1) + +/* DCR defines */ +#define DCRN_CPMSR_BASE 0x0BA +#define DCRN_CPMFR_BASE 0x0B9 + +#define DCRN_CPC0_PLLMR0_BASE 0x0F0 +#define DCRN_CPC0_BOOT_BASE 0x0F1 +#define DCRN_CPC0_CR1_BASE 0x0F2 +#define DCRN_CPC0_EPRCSR_BASE 0x0F3 +#define DCRN_CPC0_PLLMR1_BASE 0x0F4 +#define DCRN_CPC0_UCR_BASE 0x0F5 +#define DCRN_CPC0_UCR_U0DIV 0x07F +#define DCRN_CPC0_SRR_BASE 0x0F6 +#define DCRN_CPC0_JTAGID_BASE 0x0F7 +#define DCRN_CPC0_SPARE_BASE 0x0F8 +#define DCRN_CPC0_PCI_BASE 0x0F9 + + +#define IBM_CPM_GPT 0x80000000 /* GPT interface */ +#define IBM_CPM_PCI 0x40000000 /* PCI bridge */ +#define IBM_CPM_UIC 0x00010000 /* Universal Int Controller */ +#define IBM_CPM_CPU 0x00008000 /* processor core */ +#define IBM_CPM_EBC 0x00002000 /* EBC controller */ +#define IBM_CPM_SDRAM0 0x00004000 /* SDRAM memory controller */ +#define IBM_CPM_GPIO0 0x00001000 /* General Purpose IO */ +#define IBM_CPM_TMRCLK 0x00000400 /* CPU timers */ +#define IBM_CPM_PLB 0x00000100 /* PLB bus arbiter */ +#define IBM_CPM_OPB 0x00000080 /* PLB to OPB bridge */ +#define IBM_CPM_DMA 0x00000040 /* DMA controller */ +#define IBM_CPM_IIC0 0x00000010 /* IIC interface */ +#define IBM_CPM_UART1 0x00000002 /* serial port 0 */ +#define IBM_CPM_UART0 0x00000001 /* serial port 1 */ +#define DFLT_IBM4xx_PM ~(IBM_CPM_PCI | IBM_CPM_CPU | IBM_CPM_DMA \ + | IBM_CPM_OPB | IBM_CPM_EBC \ + | IBM_CPM_SDRAM0 | IBM_CPM_PLB \ + | IBM_CPM_UIC | IBM_CPM_TMRCLK) +#define DCRN_DMA0_BASE 0x100 +#define DCRN_DMA1_BASE 0x108 +#define DCRN_DMA2_BASE 0x110 +#define DCRN_DMA3_BASE 0x118 +#define DCRNCAP_DMA_SG 1 /* have DMA scatter/gather capability */ +#define DCRN_DMASR_BASE 0x120 +#define DCRN_EBC_BASE 0x012 +#define DCRN_DCP0_BASE 0x014 +#define DCRN_MAL_BASE 0x180 +#define DCRN_OCM0_BASE 0x018 +#define DCRN_PLB0_BASE 0x084 +#define DCRN_PLLMR_BASE 0x0B0 +#define DCRN_POB0_BASE 0x0A0 +#define DCRN_SDRAM0_BASE 0x010 +#define DCRN_UIC0_BASE 0x0C0 +#define UIC0 DCRN_UIC0_BASE + +#include <asm/ibm405.h> + +#endif /* __ASM_IBM405EP_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/ibm405gp.c b/arch/ppc/platforms/4xx/ibm405gp.c new file mode 100644 index 00000000000..dfd7ef3ba5f --- /dev/null +++ b/arch/ppc/platforms/4xx/ibm405gp.c @@ -0,0 +1,120 @@ +/* + * + * Copyright 2000-2001 MontaVista Software Inc. + * Original author: Armin Kuster akuster@mvista.com + * + * Module name: ibm405gp.c + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/smp.h> +#include <linux/threads.h> +#include <linux/param.h> +#include <linux/string.h> +#include <platforms/4xx/ibm405gp.h> +#include <asm/ibm4xx.h> +#include <asm/ocp.h> +#include <asm/ppc4xx_pic.h> + +static struct ocp_func_emac_data ibm405gp_emac0_def = { + .rgmii_idx = -1, /* No RGMII */ + .rgmii_mux = -1, /* No RGMII */ + .zmii_idx = -1, /* ZMII device index */ + .zmii_mux = 0, /* ZMII input of this EMAC */ + .mal_idx = 0, /* MAL device index */ + .mal_rx_chan = 0, /* MAL rx channel number */ + .mal_tx_chan = 0, /* MAL tx channel number */ + .wol_irq = 9, /* WOL interrupt number */ + .mdio_idx = -1, /* No shared MDIO */ + .tah_idx = -1, /* No TAH */ +}; +OCP_SYSFS_EMAC_DATA() + +static struct ocp_func_mal_data ibm405gp_mal0_def = { + .num_tx_chans = 1, /* Number of TX channels */ + .num_rx_chans = 1, /* Number of RX channels */ + .txeob_irq = 11, /* TX End Of Buffer IRQ */ + .rxeob_irq = 12, /* RX End Of Buffer IRQ */ + .txde_irq = 13, /* TX Descriptor Error IRQ */ + .rxde_irq = 14, /* RX Descriptor Error IRQ */ + .serr_irq = 10, /* MAL System Error IRQ */ +}; +OCP_SYSFS_MAL_DATA() + +static struct ocp_func_iic_data ibm405gp_iic0_def = { + .fast_mode = 0, /* Use standad mode (100Khz) */ +}; +OCP_SYSFS_IIC_DATA() + +struct ocp_def core_ocp[] = { + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_OPB, + .index = 0, + .paddr = 0xEF600000, + .irq = OCP_IRQ_NA, + .pm = OCP_CPM_NA, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 0, + .paddr = UART0_IO_BASE, + .irq = UART0_INT, + .pm = IBM_CPM_UART0 + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 1, + .paddr = UART1_IO_BASE, + .irq = UART1_INT, + .pm = IBM_CPM_UART1 + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_IIC, + .paddr = 0xEF600500, + .irq = 2, + .pm = IBM_CPM_IIC0, + .additions = &ibm405gp_iic0_def, + .show = &ocp_show_iic_data, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_GPIO, + .paddr = 0xEF600700, + .irq = OCP_IRQ_NA, + .pm = IBM_CPM_GPIO0 + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_MAL, + .paddr = OCP_PADDR_NA, + .irq = OCP_IRQ_NA, + .pm = OCP_CPM_NA, + .additions = &ibm405gp_mal0_def, + .show = &ocp_show_mal_data, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_EMAC, + .index = 0, + .paddr = EMAC0_BASE, + .irq = 15, + .pm = IBM_CPM_EMAC0, + .additions = &ibm405gp_emac0_def, + .show = &ocp_show_emac_data, + }, + { .vendor = OCP_VENDOR_INVALID + } +}; + +/* Polarity and triggering settings for internal interrupt sources */ +struct ppc4xx_uic_settings ppc4xx_core_uic_cfg[] __initdata = { + { .polarity = 0xffffff80, + .triggering = 0x10000000, + .ext_irq_mask = 0x0000007f, /* IRQ0 - IRQ6 */ + } +}; diff --git a/arch/ppc/platforms/4xx/ibm405gp.h b/arch/ppc/platforms/4xx/ibm405gp.h new file mode 100644 index 00000000000..b2b642e81af --- /dev/null +++ b/arch/ppc/platforms/4xx/ibm405gp.h @@ -0,0 +1,151 @@ +/* + * arch/ppc/platforms/4xx/ibm405gp.h + * + * Author: Armin Kuster akuster@mvista.com + * + * 2001 (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. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_IBM405GP_H__ +#define __ASM_IBM405GP_H__ + +#include <linux/config.h> + +/* ibm405.h at bottom of this file */ + +/* PCI + * PCI Bridge config reg definitions + * see 17-19 of manual + */ + +#define PPC405_PCI_CONFIG_ADDR 0xeec00000 +#define PPC405_PCI_CONFIG_DATA 0xeec00004 + +#define PPC405_PCI_PHY_MEM_BASE 0x80000000 /* hose_a->pci_mem_offset */ + /* setbat */ +#define PPC405_PCI_MEM_BASE PPC405_PCI_PHY_MEM_BASE /* setbat */ +#define PPC405_PCI_PHY_IO_BASE 0xe8000000 /* setbat */ +#define PPC405_PCI_IO_BASE PPC405_PCI_PHY_IO_BASE /* setbat */ + +#define PPC405_PCI_LOWER_MEM 0x80000000 /* hose_a->mem_space.start */ +#define PPC405_PCI_UPPER_MEM 0xBfffffff /* hose_a->mem_space.end */ +#define PPC405_PCI_LOWER_IO 0x00000000 /* hose_a->io_space.start */ +#define PPC405_PCI_UPPER_IO 0x0000ffff /* hose_a->io_space.end */ + +#define PPC405_ISA_IO_BASE PPC405_PCI_IO_BASE + +#define PPC4xx_PCI_IO_PADDR ((uint)PPC405_PCI_PHY_IO_BASE) +#define PPC4xx_PCI_IO_VADDR PPC4xx_PCI_IO_PADDR +#define PPC4xx_PCI_IO_SIZE ((uint)64*1024) +#define PPC4xx_PCI_CFG_PADDR ((uint)PPC405_PCI_CONFIG_ADDR) +#define PPC4xx_PCI_CFG_VADDR PPC4xx_PCI_CFG_PADDR +#define PPC4xx_PCI_CFG_SIZE ((uint)4*1024) +#define PPC4xx_PCI_LCFG_PADDR ((uint)0xef400000) +#define PPC4xx_PCI_LCFG_VADDR PPC4xx_PCI_LCFG_PADDR +#define PPC4xx_PCI_LCFG_SIZE ((uint)4*1024) +#define PPC4xx_ONB_IO_PADDR ((uint)0xef600000) +#define PPC4xx_ONB_IO_VADDR PPC4xx_ONB_IO_PADDR +#define PPC4xx_ONB_IO_SIZE ((uint)4*1024) + +/* serial port defines */ +#define RS_TABLE_SIZE 2 + +#define UART0_INT 0 +#define UART1_INT 1 + +#define PCIL0_BASE 0xEF400000 +#define UART0_IO_BASE 0xEF600300 +#define UART1_IO_BASE 0xEF600400 +#define EMAC0_BASE 0xEF600800 + +#define BD_EMAC_ADDR(e,i) bi_enetaddr[i] + +#define STD_UART_OP(num) \ + { 0, BASE_BAUD, 0, UART##num##_INT, \ + (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \ + iomem_base: (u8 *)UART##num##_IO_BASE, \ + io_type: SERIAL_IO_MEM}, + +#if defined(CONFIG_UART0_TTYS0) +#define SERIAL_DEBUG_IO_BASE UART0_IO_BASE +#define SERIAL_PORT_DFNS \ + STD_UART_OP(0) \ + STD_UART_OP(1) +#endif + +#if defined(CONFIG_UART0_TTYS1) +#define SERIAL_DEBUG_IO_BASE UART1_IO_BASE +#define SERIAL_PORT_DFNS \ + STD_UART_OP(1) \ + STD_UART_OP(0) +#endif + +/* DCR defines */ +#define DCRN_CHCR_BASE 0x0B1 +#define DCRN_CHPSR_BASE 0x0B4 +#define DCRN_CPMSR_BASE 0x0B8 +#define DCRN_CPMFR_BASE 0x0BA + +#define CHR0_U0EC 0x00000080 /* Select external clock for UART0 */ +#define CHR0_U1EC 0x00000040 /* Select external clock for UART1 */ +#define CHR0_UDIV 0x0000003E /* UART internal clock divisor */ +#define CHR1_CETE 0x00800000 /* CPU external timer enable */ + +#define DCRN_CHPSR_BASE 0x0B4 +#define PSR_PLL_FWD_MASK 0xC0000000 +#define PSR_PLL_FDBACK_MASK 0x30000000 +#define PSR_PLL_TUNING_MASK 0x0E000000 +#define PSR_PLB_CPU_MASK 0x01800000 +#define PSR_OPB_PLB_MASK 0x00600000 +#define PSR_PCI_PLB_MASK 0x00180000 +#define PSR_EB_PLB_MASK 0x00060000 +#define PSR_ROM_WIDTH_MASK 0x00018000 +#define PSR_ROM_LOC 0x00004000 +#define PSR_PCI_ASYNC_EN 0x00001000 +#define PSR_PCI_ARBIT_EN 0x00000400 + +#define IBM_CPM_IIC0 0x80000000 /* IIC interface */ +#define IBM_CPM_PCI 0x40000000 /* PCI bridge */ +#define IBM_CPM_CPU 0x20000000 /* processor core */ +#define IBM_CPM_DMA 0x10000000 /* DMA controller */ +#define IBM_CPM_OPB 0x08000000 /* PLB to OPB bridge */ +#define IBM_CPM_DCP 0x04000000 /* CodePack */ +#define IBM_CPM_EBC 0x02000000 /* ROM/SRAM peripheral controller */ +#define IBM_CPM_SDRAM0 0x01000000 /* SDRAM memory controller */ +#define IBM_CPM_PLB 0x00800000 /* PLB bus arbiter */ +#define IBM_CPM_GPIO0 0x00400000 /* General Purpose IO (??) */ +#define IBM_CPM_UART0 0x00200000 /* serial port 0 */ +#define IBM_CPM_UART1 0x00100000 /* serial port 1 */ +#define IBM_CPM_UIC 0x00080000 /* Universal Interrupt Controller */ +#define IBM_CPM_TMRCLK 0x00040000 /* CPU timers */ +#define IBM_CPM_EMAC0 0x00020000 /* on-chip ethernet MM unit */ +#define DFLT_IBM4xx_PM ~(IBM_CPM_PCI | IBM_CPM_CPU | IBM_CPM_DMA \ + | IBM_CPM_OPB | IBM_CPM_EBC \ + | IBM_CPM_SDRAM0 | IBM_CPM_PLB \ + | IBM_CPM_UIC | IBM_CPM_TMRCLK) + +#define DCRN_DMA0_BASE 0x100 +#define DCRN_DMA1_BASE 0x108 +#define DCRN_DMA2_BASE 0x110 +#define DCRN_DMA3_BASE 0x118 +#define DCRNCAP_DMA_SG 1 /* have DMA scatter/gather capability */ +#define DCRN_DMASR_BASE 0x120 +#define DCRN_EBC_BASE 0x012 +#define DCRN_DCP0_BASE 0x014 +#define DCRN_MAL_BASE 0x180 +#define DCRN_OCM0_BASE 0x018 +#define DCRN_PLB0_BASE 0x084 +#define DCRN_PLLMR_BASE 0x0B0 +#define DCRN_POB0_BASE 0x0A0 +#define DCRN_SDRAM0_BASE 0x010 +#define DCRN_UIC0_BASE 0x0C0 +#define UIC0 DCRN_UIC0_BASE + +#include <asm/ibm405.h> + +#endif /* __ASM_IBM405GP_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/ibm405gpr.c b/arch/ppc/platforms/4xx/ibm405gpr.c new file mode 100644 index 00000000000..01c8ccbc721 --- /dev/null +++ b/arch/ppc/platforms/4xx/ibm405gpr.c @@ -0,0 +1,117 @@ +/* + * arch/ppc/platforms/4xx/ibm405gpr.c + * + * Author: Armin Kuster <akuster@mvista.com> + * + * 2002 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/smp.h> +#include <linux/threads.h> +#include <linux/param.h> +#include <linux/string.h> +#include <platforms/4xx/ibm405gpr.h> +#include <asm/ibm4xx.h> +#include <asm/ocp.h> +#include <asm/ppc4xx_pic.h> + +static struct ocp_func_emac_data ibm405gpr_emac0_def = { + .rgmii_idx = -1, /* No RGMII */ + .rgmii_mux = -1, /* No RGMII */ + .zmii_idx = -1, /* ZMII device index */ + .zmii_mux = 0, /* ZMII input of this EMAC */ + .mal_idx = 0, /* MAL device index */ + .mal_rx_chan = 0, /* MAL rx channel number */ + .mal_tx_chan = 0, /* MAL tx channel number */ + .wol_irq = 9, /* WOL interrupt number */ + .mdio_idx = -1, /* No shared MDIO */ + .tah_idx = -1, /* No TAH */ +}; +OCP_SYSFS_EMAC_DATA() + +static struct ocp_func_mal_data ibm405gpr_mal0_def = { + .num_tx_chans = 1, /* Number of TX channels */ + .num_rx_chans = 1, /* Number of RX channels */ + .txeob_irq = 11, /* TX End Of Buffer IRQ */ + .rxeob_irq = 12, /* RX End Of Buffer IRQ */ + .txde_irq = 13, /* TX Descriptor Error IRQ */ + .rxde_irq = 14, /* RX Descriptor Error IRQ */ + .serr_irq = 10, /* MAL System Error IRQ */ +}; +OCP_SYSFS_MAL_DATA() + +static struct ocp_func_iic_data ibm405gpr_iic0_def = { + .fast_mode = 0, /* Use standad mode (100Khz) */ +}; + +OCP_SYSFS_IIC_DATA() + +struct ocp_def core_ocp[] = { + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_OPB, + .index = 0, + .paddr = 0xEF600000, + .irq = OCP_IRQ_NA, + .pm = OCP_CPM_NA, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 0, + .paddr = UART0_IO_BASE, + .irq = UART0_INT, + .pm = IBM_CPM_UART0 + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 1, + .paddr = UART1_IO_BASE, + .irq = UART1_INT, + .pm = IBM_CPM_UART1 + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_IIC, + .paddr = 0xEF600500, + .irq = 2, + .pm = IBM_CPM_IIC0, + .additions = &ibm405gpr_iic0_def, + .show = &ocp_show_iic_data, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_GPIO, + .paddr = 0xEF600700, + .irq = OCP_IRQ_NA, + .pm = IBM_CPM_GPIO0 + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_MAL, + .paddr = OCP_PADDR_NA, + .irq = OCP_IRQ_NA, + .pm = OCP_CPM_NA, + .additions = &ibm405gpr_mal0_def, + .show = &ocp_show_mal_data, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_EMAC, + .index = 0, + .paddr = EMAC0_BASE, + .irq = 15, + .pm = IBM_CPM_EMAC0, + .additions = &ibm405gpr_emac0_def, + .show = &ocp_show_emac_data, + }, + { .vendor = OCP_VENDOR_INVALID + } +}; + +/* Polarity and triggering settings for internal interrupt sources */ +struct ppc4xx_uic_settings ppc4xx_core_uic_cfg[] __initdata = { + { .polarity = 0xffffe000, + .triggering = 0x10000000, + .ext_irq_mask = 0x00001fff, /* IRQ7 - IRQ12, IRQ0 - IRQ6 */ + } +}; diff --git a/arch/ppc/platforms/4xx/ibm405gpr.h b/arch/ppc/platforms/4xx/ibm405gpr.h new file mode 100644 index 00000000000..45412fb4368 --- /dev/null +++ b/arch/ppc/platforms/4xx/ibm405gpr.h @@ -0,0 +1,151 @@ +/* + * arch/ppc/platforms/4xx/ibm405gpr.h + * + * Author: Armin Kuster <akuster@mvista.com> + * + * 2002 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_IBM405GPR_H__ +#define __ASM_IBM405GPR_H__ + +#include <linux/config.h> + +/* ibm405.h at bottom of this file */ + +/* PCI + * PCI Bridge config reg definitions + * see 17-19 of manual + */ + +#define PPC405_PCI_CONFIG_ADDR 0xeec00000 +#define PPC405_PCI_CONFIG_DATA 0xeec00004 + +#define PPC405_PCI_PHY_MEM_BASE 0x80000000 /* hose_a->pci_mem_offset */ + /* setbat */ +#define PPC405_PCI_MEM_BASE PPC405_PCI_PHY_MEM_BASE /* setbat */ +#define PPC405_PCI_PHY_IO_BASE 0xe8000000 /* setbat */ +#define PPC405_PCI_IO_BASE PPC405_PCI_PHY_IO_BASE /* setbat */ + +#define PPC405_PCI_LOWER_MEM 0x80000000 /* hose_a->mem_space.start */ +#define PPC405_PCI_UPPER_MEM 0xBfffffff /* hose_a->mem_space.end */ +#define PPC405_PCI_LOWER_IO 0x00000000 /* hose_a->io_space.start */ +#define PPC405_PCI_UPPER_IO 0x0000ffff /* hose_a->io_space.end */ + +#define PPC405_ISA_IO_BASE PPC405_PCI_IO_BASE + +#define PPC4xx_PCI_IO_PADDR ((uint)PPC405_PCI_PHY_IO_BASE) +#define PPC4xx_PCI_IO_VADDR PPC4xx_PCI_IO_PADDR +#define PPC4xx_PCI_IO_SIZE ((uint)64*1024) +#define PPC4xx_PCI_CFG_PADDR ((uint)PPC405_PCI_CONFIG_ADDR) +#define PPC4xx_PCI_CFG_VADDR PPC4xx_PCI_CFG_PADDR +#define PPC4xx_PCI_CFG_SIZE ((uint)4*1024) +#define PPC4xx_PCI_LCFG_PADDR ((uint)0xef400000) +#define PPC4xx_PCI_LCFG_VADDR PPC4xx_PCI_LCFG_PADDR +#define PPC4xx_PCI_LCFG_SIZE ((uint)4*1024) +#define PPC4xx_ONB_IO_PADDR ((uint)0xef600000) +#define PPC4xx_ONB_IO_VADDR PPC4xx_ONB_IO_PADDR +#define PPC4xx_ONB_IO_SIZE ((uint)4*1024) + +/* serial port defines */ +#define RS_TABLE_SIZE 2 + +#define UART0_INT 0 +#define UART1_INT 1 + +#define PCIL0_BASE 0xEF400000 +#define UART0_IO_BASE 0xEF600300 +#define UART1_IO_BASE 0xEF600400 +#define EMAC0_BASE 0xEF600800 + +#define BD_EMAC_ADDR(e,i) bi_enetaddr[i] + +#define STD_UART_OP(num) \ + { 0, BASE_BAUD, 0, UART##num##_INT, \ + (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \ + iomem_base: (u8 *)UART##num##_IO_BASE, \ + io_type: SERIAL_IO_MEM}, + +#if defined(CONFIG_UART0_TTYS0) +#define SERIAL_DEBUG_IO_BASE UART0_IO_BASE +#define SERIAL_PORT_DFNS \ + STD_UART_OP(0) \ + STD_UART_OP(1) +#endif + +#if defined(CONFIG_UART0_TTYS1) +#define SERIAL_DEBUG_IO_BASE UART1_IO_BASE +#define SERIAL_PORT_DFNS \ + STD_UART_OP(1) \ + STD_UART_OP(0) +#endif + +/* DCR defines */ +#define DCRN_CHCR_BASE 0x0B1 +#define DCRN_CHPSR_BASE 0x0B4 +#define DCRN_CPMSR_BASE 0x0B8 +#define DCRN_CPMFR_BASE 0x0BA + +#define CHR0_U0EC 0x00000080 /* Select external clock for UART0 */ +#define CHR0_U1EC 0x00000040 /* Select external clock for UART1 */ +#define CHR0_UDIV 0x0000003E /* UART internal clock divisor */ +#define CHR1_CETE 0x00800000 /* CPU external timer enable */ + +#define DCRN_CHPSR_BASE 0x0B4 +#define PSR_PLL_FWD_MASK 0xC0000000 +#define PSR_PLL_FDBACK_MASK 0x30000000 +#define PSR_PLL_TUNING_MASK 0x0E000000 +#define PSR_PLB_CPU_MASK 0x01800000 +#define PSR_OPB_PLB_MASK 0x00600000 +#define PSR_PCI_PLB_MASK 0x00180000 +#define PSR_EB_PLB_MASK 0x00060000 +#define PSR_ROM_WIDTH_MASK 0x00018000 +#define PSR_ROM_LOC 0x00004000 +#define PSR_PCI_ASYNC_EN 0x00001000 +#define PSR_PCI_ARBIT_EN 0x00000400 + +#define IBM_CPM_IIC0 0x80000000 /* IIC interface */ +#define IBM_CPM_PCI 0x40000000 /* PCI bridge */ +#define IBM_CPM_CPU 0x20000000 /* processor core */ +#define IBM_CPM_DMA 0x10000000 /* DMA controller */ +#define IBM_CPM_OPB 0x08000000 /* PLB to OPB bridge */ +#define IBM_CPM_DCP 0x04000000 /* CodePack */ +#define IBM_CPM_EBC 0x02000000 /* ROM/SRAM peripheral controller */ +#define IBM_CPM_SDRAM0 0x01000000 /* SDRAM memory controller */ +#define IBM_CPM_PLB 0x00800000 /* PLB bus arbiter */ +#define IBM_CPM_GPIO0 0x00400000 /* General Purpose IO (??) */ +#define IBM_CPM_UART0 0x00200000 /* serial port 0 */ +#define IBM_CPM_UART1 0x00100000 /* serial port 1 */ +#define IBM_CPM_UIC 0x00080000 /* Universal Interrupt Controller */ +#define IBM_CPM_TMRCLK 0x00040000 /* CPU timers */ +#define IBM_CPM_EMAC0 0x00020000 /* on-chip ethernet MM unit */ +#define DFLT_IBM4xx_PM ~(IBM_CPM_PCI | IBM_CPM_CPU | IBM_CPM_DMA \ + | IBM_CPM_OPB | IBM_CPM_EBC \ + | IBM_CPM_SDRAM0 | IBM_CPM_PLB \ + | IBM_CPM_UIC | IBM_CPM_TMRCLK) + +#define DCRN_DMA0_BASE 0x100 +#define DCRN_DMA1_BASE 0x108 +#define DCRN_DMA2_BASE 0x110 +#define DCRN_DMA3_BASE 0x118 +#define DCRNCAP_DMA_SG 1 /* have DMA scatter/gather capability */ +#define DCRN_DMASR_BASE 0x120 +#define DCRN_EBC_BASE 0x012 +#define DCRN_DCP0_BASE 0x014 +#define DCRN_MAL_BASE 0x180 +#define DCRN_OCM0_BASE 0x018 +#define DCRN_PLB0_BASE 0x084 +#define DCRN_PLLMR_BASE 0x0B0 +#define DCRN_POB0_BASE 0x0A0 +#define DCRN_SDRAM0_BASE 0x010 +#define DCRN_UIC0_BASE 0x0C0 +#define UIC0 DCRN_UIC0_BASE + +#include <asm/ibm405.h> + +#endif /* __ASM_IBM405GPR_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/ibm440gp.c b/arch/ppc/platforms/4xx/ibm440gp.c new file mode 100644 index 00000000000..27615ef8309 --- /dev/null +++ b/arch/ppc/platforms/4xx/ibm440gp.c @@ -0,0 +1,164 @@ +/* + * arch/ppc/platforms/4xx/ibm440gp.c + * + * PPC440GP I/O descriptions + * + * Matt Porter <mporter@mvista.com> + * Copyright 2002-2004 MontaVista Software Inc. + * + * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> + * Copyright (c) 2003, 2004 Zultys Technologies + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/init.h> +#include <linux/module.h> +#include <platforms/4xx/ibm440gp.h> +#include <asm/ocp.h> +#include <asm/ppc4xx_pic.h> + +static struct ocp_func_emac_data ibm440gp_emac0_def = { + .rgmii_idx = -1, /* No RGMII */ + .rgmii_mux = -1, /* No RGMII */ + .zmii_idx = 0, /* ZMII device index */ + .zmii_mux = 0, /* ZMII input of this EMAC */ + .mal_idx = 0, /* MAL device index */ + .mal_rx_chan = 0, /* MAL rx channel number */ + .mal_tx_chan = 0, /* MAL tx channel number */ + .wol_irq = 61, /* WOL interrupt number */ + .mdio_idx = -1, /* No shared MDIO */ + .tah_idx = -1, /* No TAH */ +}; + +static struct ocp_func_emac_data ibm440gp_emac1_def = { + .rgmii_idx = -1, /* No RGMII */ + .rgmii_mux = -1, /* No RGMII */ + .zmii_idx = 0, /* ZMII device index */ + .zmii_mux = 1, /* ZMII input of this EMAC */ + .mal_idx = 0, /* MAL device index */ + .mal_rx_chan = 1, /* MAL rx channel number */ + .mal_tx_chan = 2, /* MAL tx channel number */ + .wol_irq = 63, /* WOL interrupt number */ + .mdio_idx = -1, /* No shared MDIO */ + .tah_idx = -1, /* No TAH */ +}; +OCP_SYSFS_EMAC_DATA() + +static struct ocp_func_mal_data ibm440gp_mal0_def = { + .num_tx_chans = 4, /* Number of TX channels */ + .num_rx_chans = 2, /* Number of RX channels */ + .txeob_irq = 10, /* TX End Of Buffer IRQ */ + .rxeob_irq = 11, /* RX End Of Buffer IRQ */ + .txde_irq = 33, /* TX Descriptor Error IRQ */ + .rxde_irq = 34, /* RX Descriptor Error IRQ */ + .serr_irq = 32, /* MAL System Error IRQ */ +}; +OCP_SYSFS_MAL_DATA() + +static struct ocp_func_iic_data ibm440gp_iic0_def = { + .fast_mode = 0, /* Use standad mode (100Khz) */ +}; + +static struct ocp_func_iic_data ibm440gp_iic1_def = { + .fast_mode = 0, /* Use standad mode (100Khz) */ +}; +OCP_SYSFS_IIC_DATA() + +struct ocp_def core_ocp[] = { + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_OPB, + .index = 0, + .paddr = 0x0000000140000000ULL, + .irq = OCP_IRQ_NA, + .pm = OCP_CPM_NA, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 0, + .paddr = PPC440GP_UART0_ADDR, + .irq = UART0_INT, + .pm = IBM_CPM_UART0, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 1, + .paddr = PPC440GP_UART1_ADDR, + .irq = UART1_INT, + .pm = IBM_CPM_UART1, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_IIC, + .index = 0, + .paddr = 0x0000000140000400ULL, + .irq = 2, + .pm = IBM_CPM_IIC0, + .additions = &ibm440gp_iic0_def, + .show = &ocp_show_iic_data + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_IIC, + .index = 1, + .paddr = 0x0000000140000500ULL, + .irq = 3, + .pm = IBM_CPM_IIC1, + .additions = &ibm440gp_iic1_def, + .show = &ocp_show_iic_data + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_GPIO, + .index = 0, + .paddr = 0x0000000140000700ULL, + .irq = OCP_IRQ_NA, + .pm = IBM_CPM_GPIO0, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_MAL, + .paddr = OCP_PADDR_NA, + .irq = OCP_IRQ_NA, + .pm = OCP_CPM_NA, + .additions = &ibm440gp_mal0_def, + .show = &ocp_show_mal_data, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_EMAC, + .index = 0, + .paddr = 0x0000000140000800ULL, + .irq = 60, + .pm = OCP_CPM_NA, + .additions = &ibm440gp_emac0_def, + .show = &ocp_show_emac_data, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_EMAC, + .index = 1, + .paddr = 0x0000000140000900ULL, + .irq = 62, + .pm = OCP_CPM_NA, + .additions = &ibm440gp_emac1_def, + .show = &ocp_show_emac_data, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_ZMII, + .paddr = 0x0000000140000780ULL, + .irq = OCP_IRQ_NA, + .pm = OCP_CPM_NA, + }, + { .vendor = OCP_VENDOR_INVALID + } +}; + +/* Polarity and triggering settings for internal interrupt sources */ +struct ppc4xx_uic_settings ppc4xx_core_uic_cfg[] __initdata = { + { .polarity = 0xfffffe03, + .triggering = 0x01c00000, + .ext_irq_mask = 0x000001fc, /* IRQ0 - IRQ6 */ + }, + { .polarity = 0xffffc0ff, + .triggering = 0x00ff8000, + .ext_irq_mask = 0x00003f00, /* IRQ7 - IRQ12 */ + }, +}; diff --git a/arch/ppc/platforms/4xx/ibm440gp.h b/arch/ppc/platforms/4xx/ibm440gp.h new file mode 100644 index 00000000000..ae1efc03b29 --- /dev/null +++ b/arch/ppc/platforms/4xx/ibm440gp.h @@ -0,0 +1,66 @@ +/* + * arch/ppc/platforms/4xx/ibm440gp.h + * + * PPC440GP definitions + * + * Roland Dreier <roland@digitalvampire.org> + * + * Copyright 2002 Roland Dreier + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This file contains code that was originally in the files ibm44x.h + * and ebony.h, which were written by Matt Porter of MontaVista Software Inc. + */ + +#ifdef __KERNEL__ +#ifndef __PPC_PLATFORMS_IBM440GP_H +#define __PPC_PLATFORMS_IBM440GP_H + +#include <linux/config.h> + +/* UART */ +#define PPC440GP_UART0_ADDR 0x0000000140000200ULL +#define PPC440GP_UART1_ADDR 0x0000000140000300ULL +#define UART0_INT 0 +#define UART1_INT 1 + +/* Clock and Power Management */ +#define IBM_CPM_IIC0 0x80000000 /* IIC interface */ +#define IBM_CPM_IIC1 0x40000000 /* IIC interface */ +#define IBM_CPM_PCI 0x20000000 /* PCI bridge */ +#define IBM_CPM_CPU 0x02000000 /* processor core */ +#define IBM_CPM_DMA 0x01000000 /* DMA controller */ +#define IBM_CPM_BGO 0x00800000 /* PLB to OPB bus arbiter */ +#define IBM_CPM_BGI 0x00400000 /* OPB to PLB bridge */ +#define IBM_CPM_EBC 0x00200000 /* External Bux Controller */ +#define IBM_CPM_EBM 0x00100000 /* Ext Bus Master Interface */ +#define IBM_CPM_DMC 0x00080000 /* SDRAM peripheral controller */ +#define IBM_CPM_PLB 0x00040000 /* PLB bus arbiter */ +#define IBM_CPM_SRAM 0x00020000 /* SRAM memory controller */ +#define IBM_CPM_PPM 0x00002000 /* PLB Performance Monitor */ +#define IBM_CPM_UIC1 0x00001000 /* Universal Interrupt Controller */ +#define IBM_CPM_GPIO0 0x00000800 /* General Purpose IO (??) */ +#define IBM_CPM_GPT 0x00000400 /* General Purpose Timers */ +#define IBM_CPM_UART0 0x00000200 /* serial port 0 */ +#define IBM_CPM_UART1 0x00000100 /* serial port 1 */ +#define IBM_CPM_UIC0 0x00000080 /* Universal Interrupt Controller */ +#define IBM_CPM_TMRCLK 0x00000040 /* CPU timers */ + +#define DFLT_IBM4xx_PM ~(IBM_CPM_UIC | IBM_CPM_UIC1 | IBM_CPM_CPU \ + | IBM_CPM_EBC | IBM_CPM_SRAM | IBM_CPM_BGO \ + | IBM_CPM_EBM | IBM_CPM_PLB | IBM_CPM_OPB \ + | IBM_CPM_TMRCLK | IBM_CPM_DMA | IBM_CPM_PCI) +/* + * Serial port defines + */ +#define RS_TABLE_SIZE 2 + +#include <asm/ibm44x.h> +#include <syslib/ibm440gp_common.h> + +#endif /* __PPC_PLATFORMS_IBM440GP_H */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/ibm440gx.c b/arch/ppc/platforms/4xx/ibm440gx.c new file mode 100644 index 00000000000..1f38f42835b --- /dev/null +++ b/arch/ppc/platforms/4xx/ibm440gx.c @@ -0,0 +1,234 @@ +/* + * arch/ppc/platforms/4xx/ibm440gx.c + * + * PPC440GX I/O descriptions + * + * Matt Porter <mporter@mvista.com> + * Copyright 2002-2004 MontaVista Software Inc. + * + * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> + * Copyright (c) 2003, 2004 Zultys Technologies + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/init.h> +#include <linux/module.h> +#include <platforms/4xx/ibm440gx.h> +#include <asm/ocp.h> +#include <asm/ppc4xx_pic.h> + +static struct ocp_func_emac_data ibm440gx_emac0_def = { + .rgmii_idx = -1, /* No RGMII */ + .rgmii_mux = -1, /* No RGMII */ + .zmii_idx = 0, /* ZMII device index */ + .zmii_mux = 0, /* ZMII input of this EMAC */ + .mal_idx = 0, /* MAL device index */ + .mal_rx_chan = 0, /* MAL rx channel number */ + .mal_tx_chan = 0, /* MAL tx channel number */ + .wol_irq = 61, /* WOL interrupt number */ + .mdio_idx = -1, /* No shared MDIO */ + .tah_idx = -1, /* No TAH */ +}; + +static struct ocp_func_emac_data ibm440gx_emac1_def = { + .rgmii_idx = -1, /* No RGMII */ + .rgmii_mux = -1, /* No RGMII */ + .zmii_idx = 0, /* ZMII device index */ + .zmii_mux = 1, /* ZMII input of this EMAC */ + .mal_idx = 0, /* MAL device index */ + .mal_rx_chan = 1, /* MAL rx channel number */ + .mal_tx_chan = 1, /* MAL tx channel number */ + .wol_irq = 63, /* WOL interrupt number */ + .mdio_idx = -1, /* No shared MDIO */ + .tah_idx = -1, /* No TAH */ +}; + +static struct ocp_func_emac_data ibm440gx_emac2_def = { + .rgmii_idx = 0, /* RGMII device index */ + .rgmii_mux = 0, /* RGMII input of this EMAC */ + .zmii_idx = 0, /* ZMII device index */ + .zmii_mux = 2, /* ZMII input of this EMAC */ + .mal_idx = 0, /* MAL device index */ + .mal_rx_chan = 2, /* MAL rx channel number */ + .mal_tx_chan = 2, /* MAL tx channel number */ + .wol_irq = 65, /* WOL interrupt number */ + .mdio_idx = -1, /* No shared MDIO */ + .tah_idx = 0, /* TAH device index */ + .jumbo = 1, /* Jumbo frames supported */ +}; + +static struct ocp_func_emac_data ibm440gx_emac3_def = { + .rgmii_idx = 0, /* RGMII device index */ + .rgmii_mux = 1, /* RGMII input of this EMAC */ + .zmii_idx = 0, /* ZMII device index */ + .zmii_mux = 3, /* ZMII input of this EMAC */ + .mal_idx = 0, /* MAL device index */ + .mal_rx_chan = 3, /* MAL rx channel number */ + .mal_tx_chan = 3, /* MAL tx channel number */ + .wol_irq = 67, /* WOL interrupt number */ + .mdio_idx = -1, /* No shared MDIO */ + .tah_idx = 1, /* TAH device index */ + .jumbo = 1, /* Jumbo frames supported */ +}; +OCP_SYSFS_EMAC_DATA() + +static struct ocp_func_mal_data ibm440gx_mal0_def = { + .num_tx_chans = 4, /* Number of TX channels */ + .num_rx_chans = 4, /* Number of RX channels */ + .txeob_irq = 10, /* TX End Of Buffer IRQ */ + .rxeob_irq = 11, /* RX End Of Buffer IRQ */ + .txde_irq = 33, /* TX Descriptor Error IRQ */ + .rxde_irq = 34, /* RX Descriptor Error IRQ */ + .serr_irq = 32, /* MAL System Error IRQ */ +}; +OCP_SYSFS_MAL_DATA() + +static struct ocp_func_iic_data ibm440gx_iic0_def = { + .fast_mode = 0, /* Use standad mode (100Khz) */ +}; + +static struct ocp_func_iic_data ibm440gx_iic1_def = { + .fast_mode = 0, /* Use standad mode (100Khz) */ +}; +OCP_SYSFS_IIC_DATA() + +struct ocp_def core_ocp[] = { + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_OPB, + .index = 0, + .paddr = 0x0000000140000000ULL, + .irq = OCP_IRQ_NA, + .pm = OCP_CPM_NA, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 0, + .paddr = PPC440GX_UART0_ADDR, + .irq = UART0_INT, + .pm = IBM_CPM_UART0, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 1, + .paddr = PPC440GX_UART1_ADDR, + .irq = UART1_INT, + .pm = IBM_CPM_UART1, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_IIC, + .index = 0, + .paddr = 0x0000000140000400ULL, + .irq = 2, + .pm = IBM_CPM_IIC0, + .additions = &ibm440gx_iic0_def, + .show = &ocp_show_iic_data + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_IIC, + .index = 1, + .paddr = 0x0000000140000500ULL, + .irq = 3, + .pm = IBM_CPM_IIC1, + .additions = &ibm440gx_iic1_def, + .show = &ocp_show_iic_data + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_GPIO, + .index = 0, + .paddr = 0x0000000140000700ULL, + .irq = OCP_IRQ_NA, + .pm = IBM_CPM_GPIO0, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_MAL, + .paddr = OCP_PADDR_NA, + .irq = OCP_IRQ_NA, + .pm = OCP_CPM_NA, + .additions = &ibm440gx_mal0_def, + .show = &ocp_show_mal_data, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_EMAC, + .index = 0, + .paddr = 0x0000000140000800ULL, + .irq = 60, + .pm = OCP_CPM_NA, + .additions = &ibm440gx_emac0_def, + .show = &ocp_show_emac_data, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_EMAC, + .index = 1, + .paddr = 0x0000000140000900ULL, + .irq = 62, + .pm = OCP_CPM_NA, + .additions = &ibm440gx_emac1_def, + .show = &ocp_show_emac_data, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_EMAC, + .index = 2, + .paddr = 0x0000000140000C00ULL, + .irq = 64, + .pm = OCP_CPM_NA, + .additions = &ibm440gx_emac2_def, + .show = &ocp_show_emac_data, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_EMAC, + .index = 3, + .paddr = 0x0000000140000E00ULL, + .irq = 66, + .pm = OCP_CPM_NA, + .additions = &ibm440gx_emac3_def, + .show = &ocp_show_emac_data, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_RGMII, + .paddr = 0x0000000140000790ULL, + .irq = OCP_IRQ_NA, + .pm = OCP_CPM_NA, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_ZMII, + .paddr = 0x0000000140000780ULL, + .irq = OCP_IRQ_NA, + .pm = OCP_CPM_NA, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_TAH, + .index = 0, + .paddr = 0x0000000140000b50ULL, + .irq = 68, + .pm = OCP_CPM_NA, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_TAH, + .index = 1, + .paddr = 0x0000000140000d50ULL, + .irq = 69, + .pm = OCP_CPM_NA, + }, + { .vendor = OCP_VENDOR_INVALID + } +}; + +/* Polarity and triggering settings for internal interrupt sources */ +struct ppc4xx_uic_settings ppc4xx_core_uic_cfg[] __initdata = { + { .polarity = 0xfffffe03, + .triggering = 0x01c00000, + .ext_irq_mask = 0x000001fc, /* IRQ0 - IRQ6 */ + }, + { .polarity = 0xffffc0ff, + .triggering = 0x00ff8000, + .ext_irq_mask = 0x00003f00, /* IRQ7 - IRQ12 */ + }, + { .polarity = 0xffff83ff, + .triggering = 0x000f83c0, + .ext_irq_mask = 0x00007c00, /* IRQ13 - IRQ17 */ + }, +}; diff --git a/arch/ppc/platforms/4xx/ibm440gx.h b/arch/ppc/platforms/4xx/ibm440gx.h new file mode 100644 index 00000000000..0b59d8dcd03 --- /dev/null +++ b/arch/ppc/platforms/4xx/ibm440gx.h @@ -0,0 +1,74 @@ +/* + * arch/ppc/platforms/ibm440gx.h + * + * PPC440GX definitions + * + * Matt Porter <mporter@mvista.com> + * + * Copyright 2002 Roland Dreier + * Copyright 2003 MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifdef __KERNEL__ +#ifndef __PPC_PLATFORMS_IBM440GX_H +#define __PPC_PLATFORMS_IBM440GX_H + +#include <linux/config.h> + +#include <asm/ibm44x.h> + +/* UART */ +#define PPC440GX_UART0_ADDR 0x0000000140000200ULL +#define PPC440GX_UART1_ADDR 0x0000000140000300ULL +#define UART0_INT 0 +#define UART1_INT 1 + +/* Clock and Power Management */ +#define IBM_CPM_IIC0 0x80000000 /* IIC interface */ +#define IBM_CPM_IIC1 0x40000000 /* IIC interface */ +#define IBM_CPM_PCI 0x20000000 /* PCI bridge */ +#define IBM_CPM_RGMII 0x10000000 /* RGMII */ +#define IBM_CPM_TAHOE0 0x08000000 /* TAHOE 0 */ +#define IBM_CPM_TAHOE1 0x04000000 /* TAHOE 1 */ +#define IBM_CPM_CPU 0x02000000 /* processor core */ +#define IBM_CPM_DMA 0x01000000 /* DMA controller */ +#define IBM_CPM_BGO 0x00800000 /* PLB to OPB bus arbiter */ +#define IBM_CPM_BGI 0x00400000 /* OPB to PLB bridge */ +#define IBM_CPM_EBC 0x00200000 /* External Bux Controller */ +#define IBM_CPM_EBM 0x00100000 /* Ext Bus Master Interface */ +#define IBM_CPM_DMC 0x00080000 /* SDRAM peripheral controller */ +#define IBM_CPM_PLB 0x00040000 /* PLB bus arbiter */ +#define IBM_CPM_SRAM 0x00020000 /* SRAM memory controller */ +#define IBM_CPM_PPM 0x00002000 /* PLB Performance Monitor */ +#define IBM_CPM_UIC1 0x00001000 /* Universal Interrupt Controller */ +#define IBM_CPM_GPIO0 0x00000800 /* General Purpose IO (??) */ +#define IBM_CPM_GPT 0x00000400 /* General Purpose Timers */ +#define IBM_CPM_UART0 0x00000200 /* serial port 0 */ +#define IBM_CPM_UART1 0x00000100 /* serial port 1 */ +#define IBM_CPM_UIC0 0x00000080 /* Universal Interrupt Controller */ +#define IBM_CPM_TMRCLK 0x00000040 /* CPU timers */ +#define IBM_CPM_EMAC0 0x00000020 /* EMAC 0 */ +#define IBM_CPM_EMAC1 0x00000010 /* EMAC 1 */ +#define IBM_CPM_EMAC2 0x00000008 /* EMAC 2 */ +#define IBM_CPM_EMAC3 0x00000004 /* EMAC 3 */ + +#define DFLT_IBM4xx_PM ~(IBM_CPM_UIC | IBM_CPM_UIC1 | IBM_CPM_CPU \ + | IBM_CPM_EBC | IBM_CPM_SRAM | IBM_CPM_BGO \ + | IBM_CPM_EBM | IBM_CPM_PLB | IBM_CPM_OPB \ + | IBM_CPM_TMRCLK | IBM_CPM_DMA | IBM_CPM_PCI \ + | IBM_CPM_TAHOE0 | IBM_CPM_TAHOE1 \ + | IBM_CPM_EMAC0 | IBM_CPM_EMAC1 \ + | IBM_CPM_EMAC2 | IBM_CPM_EMAC3 ) +/* + * Serial port defines + */ +#define RS_TABLE_SIZE 2 + +#endif /* __PPC_PLATFORMS_IBM440GX_H */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/ibm440sp.c b/arch/ppc/platforms/4xx/ibm440sp.c new file mode 100644 index 00000000000..a203efb47ab --- /dev/null +++ b/arch/ppc/platforms/4xx/ibm440sp.c @@ -0,0 +1,131 @@ +/* + * arch/ppc/platforms/4xx/ibm440sp.c + * + * PPC440SP I/O descriptions + * + * Matt Porter <mporter@kernel.crashing.org> + * Copyright 2002-2005 MontaVista Software Inc. + * + * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> + * Copyright (c) 2003, 2004 Zultys Technologies + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/init.h> +#include <linux/module.h> +#include <platforms/4xx/ibm440sp.h> +#include <asm/ocp.h> + +static struct ocp_func_emac_data ibm440sp_emac0_def = { + .rgmii_idx = -1, /* No RGMII */ + .rgmii_mux = -1, /* No RGMII */ + .zmii_idx = -1, /* No ZMII */ + .zmii_mux = -1, /* No ZMII */ + .mal_idx = 0, /* MAL device index */ + .mal_rx_chan = 0, /* MAL rx channel number */ + .mal_tx_chan = 0, /* MAL tx channel number */ + .wol_irq = 61, /* WOL interrupt number */ + .mdio_idx = -1, /* No shared MDIO */ + .tah_idx = -1, /* No TAH */ + .jumbo = 1, /* Jumbo frames supported */ +}; +OCP_SYSFS_EMAC_DATA() + +static struct ocp_func_mal_data ibm440sp_mal0_def = { + .num_tx_chans = 4, /* Number of TX channels */ + .num_rx_chans = 4, /* Number of RX channels */ + .txeob_irq = 38, /* TX End Of Buffer IRQ */ + .rxeob_irq = 39, /* RX End Of Buffer IRQ */ + .txde_irq = 34, /* TX Descriptor Error IRQ */ + .rxde_irq = 35, /* RX Descriptor Error IRQ */ + .serr_irq = 33, /* MAL System Error IRQ */ +}; +OCP_SYSFS_MAL_DATA() + +static struct ocp_func_iic_data ibm440sp_iic0_def = { + .fast_mode = 0, /* Use standad mode (100Khz) */ +}; + +static struct ocp_func_iic_data ibm440sp_iic1_def = { + .fast_mode = 0, /* Use standad mode (100Khz) */ +}; +OCP_SYSFS_IIC_DATA() + +struct ocp_def core_ocp[] = { + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_OPB, + .index = 0, + .paddr = 0x0000000140000000ULL, + .irq = OCP_IRQ_NA, + .pm = OCP_CPM_NA, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 0, + .paddr = PPC440SP_UART0_ADDR, + .irq = UART0_INT, + .pm = IBM_CPM_UART0, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 1, + .paddr = PPC440SP_UART1_ADDR, + .irq = UART1_INT, + .pm = IBM_CPM_UART1, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 2, + .paddr = PPC440SP_UART2_ADDR, + .irq = UART2_INT, + .pm = IBM_CPM_UART2, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_IIC, + .index = 0, + .paddr = 0x00000001f0000400ULL, + .irq = 2, + .pm = IBM_CPM_IIC0, + .additions = &ibm440sp_iic0_def, + .show = &ocp_show_iic_data + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_IIC, + .index = 1, + .paddr = 0x00000001f0000500ULL, + .irq = 3, + .pm = IBM_CPM_IIC1, + .additions = &ibm440sp_iic1_def, + .show = &ocp_show_iic_data + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_GPIO, + .index = 0, + .paddr = 0x00000001f0000700ULL, + .irq = OCP_IRQ_NA, + .pm = IBM_CPM_GPIO0, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_MAL, + .paddr = OCP_PADDR_NA, + .irq = OCP_IRQ_NA, + .pm = OCP_CPM_NA, + .additions = &ibm440sp_mal0_def, + .show = &ocp_show_mal_data, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_EMAC, + .index = 0, + .paddr = 0x00000001f0000800ULL, + .irq = 60, + .pm = OCP_CPM_NA, + .additions = &ibm440sp_emac0_def, + .show = &ocp_show_emac_data, + }, + { .vendor = OCP_VENDOR_INVALID + } +}; diff --git a/arch/ppc/platforms/4xx/ibm440sp.h b/arch/ppc/platforms/4xx/ibm440sp.h new file mode 100644 index 00000000000..c71e46a18b9 --- /dev/null +++ b/arch/ppc/platforms/4xx/ibm440sp.h @@ -0,0 +1,64 @@ +/* + * arch/ppc/platforms/4xx/ibm440sp.h + * + * PPC440SP definitions + * + * Matt Porter <mporter@kernel.crashing.org> + * + * Copyright 2004-2005 MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifdef __KERNEL__ +#ifndef __PPC_PLATFORMS_IBM440SP_H +#define __PPC_PLATFORMS_IBM440SP_H + +#include <linux/config.h> + +#include <asm/ibm44x.h> + +/* UART */ +#define PPC440SP_UART0_ADDR 0x00000001f0000200ULL +#define PPC440SP_UART1_ADDR 0x00000001f0000300ULL +#define PPC440SP_UART2_ADDR 0x00000001f0000600ULL +#define UART0_INT 0 +#define UART1_INT 1 +#define UART2_INT 2 + +/* Clock and Power Management */ +#define IBM_CPM_IIC0 0x80000000 /* IIC interface */ +#define IBM_CPM_IIC1 0x40000000 /* IIC interface */ +#define IBM_CPM_PCI 0x20000000 /* PCI bridge */ +#define IBM_CPM_CPU 0x02000000 /* processor core */ +#define IBM_CPM_DMA 0x01000000 /* DMA controller */ +#define IBM_CPM_BGO 0x00800000 /* PLB to OPB bus arbiter */ +#define IBM_CPM_BGI 0x00400000 /* OPB to PLB bridge */ +#define IBM_CPM_EBC 0x00200000 /* External Bux Controller */ +#define IBM_CPM_EBM 0x00100000 /* Ext Bus Master Interface */ +#define IBM_CPM_DMC 0x00080000 /* SDRAM peripheral controller */ +#define IBM_CPM_PLB 0x00040000 /* PLB bus arbiter */ +#define IBM_CPM_SRAM 0x00020000 /* SRAM memory controller */ +#define IBM_CPM_PPM 0x00002000 /* PLB Performance Monitor */ +#define IBM_CPM_UIC1 0x00001000 /* Universal Interrupt Controller */ +#define IBM_CPM_GPIO0 0x00000800 /* General Purpose IO (??) */ +#define IBM_CPM_GPT 0x00000400 /* General Purpose Timers */ +#define IBM_CPM_UART0 0x00000200 /* serial port 0 */ +#define IBM_CPM_UART1 0x00000100 /* serial port 1 */ +#define IBM_CPM_UART2 0x00000100 /* serial port 1 */ +#define IBM_CPM_UIC0 0x00000080 /* Universal Interrupt Controller */ +#define IBM_CPM_TMRCLK 0x00000040 /* CPU timers */ +#define IBM_CPM_EMAC0 0x00000020 /* EMAC 0 */ + +#define DFLT_IBM4xx_PM ~(IBM_CPM_UIC | IBM_CPM_UIC1 | IBM_CPM_CPU \ + | IBM_CPM_EBC | IBM_CPM_SRAM | IBM_CPM_BGO \ + | IBM_CPM_EBM | IBM_CPM_PLB | IBM_CPM_OPB \ + | IBM_CPM_TMRCLK | IBM_CPM_DMA | IBM_CPM_PCI \ + | IBM_CPM_TAHOE0 | IBM_CPM_TAHOE1 \ + | IBM_CPM_EMAC0 | IBM_CPM_EMAC1 \ + | IBM_CPM_EMAC2 | IBM_CPM_EMAC3 ) +#endif /* __PPC_PLATFORMS_IBM440SP_H */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/ibmnp405h.c b/arch/ppc/platforms/4xx/ibmnp405h.c new file mode 100644 index 00000000000..ecdc5be6ae2 --- /dev/null +++ b/arch/ppc/platforms/4xx/ibmnp405h.c @@ -0,0 +1,172 @@ +/* + * arch/ppc/platforms/4xx/ibmnp405h.c + * + * Author: Armin Kuster <akuster@mvista.com> + * + * 2000-2002 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <asm/ocp.h> +#include <platforms/4xx/ibmnp405h.h> + +static struct ocp_func_emac_data ibmnp405h_emac0_def = { + .rgmii_idx = -1, /* No RGMII */ + .rgmii_mux = -1, /* No RGMII */ + .zmii_idx = 0, /* ZMII device index */ + .zmii_mux = 0, /* ZMII input of this EMAC */ + .mal_idx = 0, /* MAL device index */ + .mal_rx_chan = 0, /* MAL rx channel number */ + .mal_tx_chan = 0, /* MAL tx channel number */ + .wol_irq = 41, /* WOL interrupt number */ + .mdio_idx = -1, /* No shared MDIO */ + .tah_idx = -1, /* No TAH */ +}; + +static struct ocp_func_emac_data ibmnp405h_emac1_def = { + .rgmii_idx = -1, /* No RGMII */ + .rgmii_mux = -1, /* No RGMII */ + .zmii_idx = 0, /* ZMII device index */ + .zmii_mux = 1, /* ZMII input of this EMAC */ + .mal_idx = 0, /* MAL device index */ + .mal_rx_chan = 1, /* MAL rx channel number */ + .mal_tx_chan = 1, /* MAL tx channel number */ + .wol_irq = 41, /* WOL interrupt number */ + .mdio_idx = -1, /* No shared MDIO */ + .tah_idx = -1, /* No TAH */ +}; +static struct ocp_func_emac_data ibmnp405h_emac2_def = { + .rgmii_idx = -1, /* No RGMII */ + .rgmii_mux = -1, /* No RGMII */ + .zmii_idx = 0, /* ZMII device index */ + .zmii_mux = 2, /* ZMII input of this EMAC */ + .mal_idx = 0, /* MAL device index */ + .mal_rx_chan = 2, /* MAL rx channel number */ + .mal_tx_chan = 2, /* MAL tx channel number */ + .wol_irq = 41, /* WOL interrupt number */ + .mdio_idx = -1, /* No shared MDIO */ + .tah_idx = -1, /* No TAH */ +}; +static struct ocp_func_emac_data ibmnp405h_emac3_def = { + .rgmii_idx = -1, /* No RGMII */ + .rgmii_mux = -1, /* No RGMII */ + .zmii_idx = 0, /* ZMII device index */ + .zmii_mux = 3, /* ZMII input of this EMAC */ + .mal_idx = 0, /* MAL device index */ + .mal_rx_chan = 3, /* MAL rx channel number */ + .mal_tx_chan = 3, /* MAL tx channel number */ + .wol_irq = 41, /* WOL interrupt number */ + .mdio_idx = -1, /* No shared MDIO */ + .tah_idx = -1, /* No TAH */ +}; +OCP_SYSFS_EMAC_DATA() + +static struct ocp_func_mal_data ibmnp405h_mal0_def = { + .num_tx_chans = 8, /* Number of TX channels */ + .num_rx_chans = 4, /* Number of RX channels */ + .txeob_irq = 17, /* TX End Of Buffer IRQ */ + .rxeob_irq = 18, /* RX End Of Buffer IRQ */ + .txde_irq = 46, /* TX Descriptor Error IRQ */ + .rxde_irq = 47, /* RX Descriptor Error IRQ */ + .serr_irq = 45, /* MAL System Error IRQ */ +}; +OCP_SYSFS_MAL_DATA() + +static struct ocp_func_iic_data ibmnp405h_iic0_def = { + .fast_mode = 0, /* Use standad mode (100Khz) */ +}; +OCP_SYSFS_IIC_DATA() + +struct ocp_def core_ocp[] = { + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_OPB, + .index = 0, + .paddr = 0xEF600000, + .irq = OCP_IRQ_NA, + .pm = OCP_CPM_NA, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 0, + .paddr = UART0_IO_BASE, + .irq = UART0_INT, + .pm = IBM_CPM_UART0 + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 1, + .paddr = UART1_IO_BASE, + .irq = UART1_INT, + .pm = IBM_CPM_UART1 + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_IIC, + .paddr = 0xEF600500, + .irq = 2, + .pm = IBM_CPM_IIC0, + .additions = &ibmnp405h_iic0_def, + .show = &ocp_show_iic_data + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_GPIO, + .paddr = 0xEF600700, + .irq = OCP_IRQ_NA, + .pm = IBM_CPM_GPIO0 + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_MAL, + .paddr = OCP_PADDR_NA, + .irq = OCP_IRQ_NA, + .pm = OCP_CPM_NA, + .additions = &ibmnp405h_mal0_def, + .show = &ocp_show_mal_data, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_EMAC, + .index = 0, + .paddr = EMAC0_BASE, + .irq = 37, + .pm = IBM_CPM_EMAC0, + .additions = &ibmnp405h_emac0_def, + .show = &ocp_show_emac_data, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_EMAC, + .index = 1, + .paddr = 0xEF600900, + .irq = 38, + .pm = IBM_CPM_EMAC1, + .additions = &ibmnp405h_emac1_def, + .show = &ocp_show_emac_data, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_EMAC, + .index = 2, + .paddr = 0xEF600a00, + .irq = 39, + .pm = IBM_CPM_EMAC2, + .additions = &ibmnp405h_emac2_def, + .show = &ocp_show_emac_data, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_EMAC, + .index = 3, + .paddr = 0xEF600b00, + .irq = 40, + .pm = IBM_CPM_EMAC3, + .additions = &ibmnp405h_emac3_def, + .show = &ocp_show_emac_data, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_ZMII, + .paddr = 0xEF600C10, + .irq = OCP_IRQ_NA, + .pm = OCP_CPM_NA, + }, + { .vendor = OCP_VENDOR_INVALID + } +}; diff --git a/arch/ppc/platforms/4xx/ibmnp405h.h b/arch/ppc/platforms/4xx/ibmnp405h.h new file mode 100644 index 00000000000..e2c2b06128c --- /dev/null +++ b/arch/ppc/platforms/4xx/ibmnp405h.h @@ -0,0 +1,157 @@ +/* + * arch/ppc/platforms/4xx/ibmnp405h.h + * + * Author: Armin Kuster <akuster@mvista.com> + * + * 2002 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_IBMNP405H_H__ +#define __ASM_IBMNP405H_H__ + +#include <linux/config.h> + +/* ibm405.h at bottom of this file */ + +#define PPC405_PCI_CONFIG_ADDR 0xeec00000 +#define PPC405_PCI_CONFIG_DATA 0xeec00004 +#define PPC405_PCI_PHY_MEM_BASE 0x80000000 /* hose_a->pci_mem_offset */ + /* setbat */ +#define PPC405_PCI_MEM_BASE PPC405_PCI_PHY_MEM_BASE /* setbat */ +#define PPC405_PCI_PHY_IO_BASE 0xe8000000 /* setbat */ +#define PPC405_PCI_IO_BASE PPC405_PCI_PHY_IO_BASE /* setbat */ + +#define PPC405_PCI_LOWER_MEM 0x00000000 /* hose_a->mem_space.start */ +#define PPC405_PCI_UPPER_MEM 0xBfffffff /* hose_a->mem_space.end */ +#define PPC405_PCI_LOWER_IO 0x00000000 /* hose_a->io_space.start */ +#define PPC405_PCI_UPPER_IO 0x0000ffff /* hose_a->io_space.end */ + +#define PPC405_ISA_IO_BASE PPC405_PCI_IO_BASE + +#define PPC4xx_PCI_IO_ADDR ((uint)PPC405_PCI_PHY_IO_BASE) +#define PPC4xx_PCI_IO_SIZE ((uint)64*1024) +#define PPC4xx_PCI_CFG_ADDR ((uint)PPC405_PCI_CONFIG_ADDR) +#define PPC4xx_PCI_CFG_SIZE ((uint)4*1024) +#define PPC4xx_PCI_LCFG_ADDR ((uint)0xef400000) +#define PPC4xx_PCI_LCFG_SIZE ((uint)4*1024) +#define PPC4xx_ONB_IO_ADDR ((uint)0xef600000) +#define PPC4xx_ONB_IO_SIZE ((uint)4*1024) + +/* serial port defines */ +#define RS_TABLE_SIZE 4 + +#define UART0_INT 0 +#define UART1_INT 1 +#define PCIL0_BASE 0xEF400000 +#define UART0_IO_BASE 0xEF600300 +#define UART1_IO_BASE 0xEF600400 +#define OPB0_BASE 0xEF600600 +#define EMAC0_BASE 0xEF600800 + +#define BD_EMAC_ADDR(e,i) bi_enetaddr[e][i] + +#define STD_UART_OP(num) \ + { 0, BASE_BAUD, 0, UART##num##_INT, \ + (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \ + iomem_base:(u8 *) UART##num##_IO_BASE, \ + io_type: SERIAL_IO_MEM}, + +#if defined(CONFIG_UART0_TTYS0) +#define SERIAL_DEBUG_IO_BASE UART0_IO_BASE +#define SERIAL_PORT_DFNS \ + STD_UART_OP(0) \ + STD_UART_OP(1) +#endif + +#if defined(CONFIG_UART0_TTYS1) +#define SERIAL_DEBUG_IO_BASE UART0_IO_BASE +#define SERIAL_PORT_DFNS \ + STD_UART_OP(1) \ + STD_UART_OP(0) +#endif + +/* DCR defines */ +/* ------------------------------------------------------------------------- */ + +#define DCRN_CHCR_BASE 0x0F1 +#define DCRN_CHPSR_BASE 0x0B4 +#define DCRN_CPMSR_BASE 0x0BA +#define DCRN_CPMFR_BASE 0x0B9 +#define DCRN_CPMER_BASE 0x0B8 + +/* CPM Clocking & Power Mangement defines */ +#define IBM_CPM_PCI 0x40000000 /* PCI */ +#define IBM_CPM_EMAC2 0x20000000 /* EMAC 2 MII */ +#define IBM_CPM_EMAC3 0x04000000 /* EMAC 3 MII */ +#define IBM_CPM_EMAC0 0x00800000 /* EMAC 0 MII */ +#define IBM_CPM_EMAC1 0x00100000 /* EMAC 1 MII */ +#define IBM_CPM_EMMII 0 /* Shift value for MII */ +#define IBM_CPM_EMRX 1 /* Shift value for recv */ +#define IBM_CPM_EMTX 2 /* Shift value for MAC */ +#define IBM_CPM_UIC1 0x00020000 /* Universal Interrupt Controller */ +#define IBM_CPM_UIC0 0x00010000 /* Universal Interrupt Controller */ +#define IBM_CPM_CPU 0x00008000 /* processor core */ +#define IBM_CPM_EBC 0x00004000 /* ROM/SRAM peripheral controller */ +#define IBM_CPM_SDRAM0 0x00002000 /* SDRAM memory controller */ +#define IBM_CPM_GPIO0 0x00001000 /* General Purpose IO (??) */ +#define IBM_CPM_HDLC 0x00000800 /* HDCL */ +#define IBM_CPM_TMRCLK 0x00000400 /* CPU timers */ +#define IBM_CPM_PLB 0x00000100 /* PLB bus arbiter */ +#define IBM_CPM_OPB 0x00000080 /* PLB to OPB bridge */ +#define IBM_CPM_DMA 0x00000040 /* DMA controller */ +#define IBM_CPM_IIC0 0x00000010 /* IIC interface */ +#define IBM_CPM_UART0 0x00000002 /* serial port 0 */ +#define IBM_CPM_UART1 0x00000001 /* serial port 1 */ +/* this is the default setting for devices put to sleep when booting */ + +#define DFLT_IBM4xx_PM ~(IBM_CPM_UIC0 | IBM_CPM_UIC1 | IBM_CPM_CPU \ + | IBM_CPM_EBC | IBM_CPM_SDRAM0 | IBM_CPM_PLB \ + | IBM_CPM_OPB | IBM_CPM_TMRCLK | IBM_CPM_DMA \ + | IBM_CPM_EMAC0 | IBM_CPM_EMAC1 | IBM_CPM_EMAC2 \ + | IBM_CPM_EMAC3 | IBM_CPM_PCI) + +#define DCRN_DMA0_BASE 0x100 +#define DCRN_DMA1_BASE 0x108 +#define DCRN_DMA2_BASE 0x110 +#define DCRN_DMA3_BASE 0x118 +#define DCRNCAP_DMA_SG 1 /* have DMA scatter/gather capability */ +#define DCRN_DMASR_BASE 0x120 +#define DCRN_EBC_BASE 0x012 +#define DCRN_DCP0_BASE 0x014 +#define DCRN_MAL_BASE 0x180 +#define DCRN_OCM0_BASE 0x018 +#define DCRN_PLB0_BASE 0x084 +#define DCRN_PLLMR_BASE 0x0B0 +#define DCRN_POB0_BASE 0x0A0 +#define DCRN_SDRAM0_BASE 0x010 +#define DCRN_UIC0_BASE 0x0C0 +#define DCRN_UIC1_BASE 0x0D0 +#define DCRN_CPC0_EPRCSR 0x0F3 + +#define UIC0_UIC1NC 0x00000002 + +#define CHR1_CETE 0x00000004 /* CPU external timer enable */ +#define UIC0 DCRN_UIC0_BASE +#define UIC1 DCRN_UIC1_BASE + +#undef NR_UICS +#define NR_UICS 2 + +/* EMAC DCRN's FIXME: armin */ +#define DCRN_MALRXCTP2R(base) ((base) + 0x42) /* Channel Rx 2 Channel Table Pointer */ +#define DCRN_MALRXCTP3R(base) ((base) + 0x43) /* Channel Rx 3 Channel Table Pointer */ +#define DCRN_MALTXCTP4R(base) ((base) + 0x24) /* Channel Tx 4 Channel Table Pointer */ +#define DCRN_MALTXCTP5R(base) ((base) + 0x25) /* Channel Tx 5 Channel Table Pointer */ +#define DCRN_MALTXCTP6R(base) ((base) + 0x26) /* Channel Tx 6 Channel Table Pointer */ +#define DCRN_MALTXCTP7R(base) ((base) + 0x27) /* Channel Tx 7 Channel Table Pointer */ +#define DCRN_MALRCBS2(base) ((base) + 0x62) /* Channel Rx 2 Channel Buffer Size */ +#define DCRN_MALRCBS3(base) ((base) + 0x63) /* Channel Rx 3 Channel Buffer Size */ + +#include <asm/ibm405.h> + +#endif /* __ASM_IBMNP405H_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/ibmstb4.c b/arch/ppc/platforms/4xx/ibmstb4.c new file mode 100644 index 00000000000..874d16bab73 --- /dev/null +++ b/arch/ppc/platforms/4xx/ibmstb4.c @@ -0,0 +1,83 @@ +/* + * arch/ppc/platforms/4xx/ibmstb4.c + * + * Author: Armin Kuster <akuster@mvista.com> + * + * 2000-2001 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include <linux/init.h> +#include <asm/ocp.h> +#include <platforms/4xx/ibmstb4.h> + +static struct ocp_func_iic_data ibmstb4_iic0_def = { + .fast_mode = 0, /* Use standad mode (100Khz) */ +}; + +static struct ocp_func_iic_data ibmstb4_iic1_def = { + .fast_mode = 0, /* Use standad mode (100Khz) */ +}; +OCP_SYSFS_IIC_DATA() + +struct ocp_def core_ocp[] __initdata = { + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 0, + .paddr = UART0_IO_BASE, + .irq = UART0_INT, + .pm = IBM_CPM_UART0, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 1, + .paddr = UART1_IO_BASE, + .irq = UART1_INT, + .pm = IBM_CPM_UART1, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 2, + .paddr = UART2_IO_BASE, + .irq = UART2_INT, + .pm = IBM_CPM_UART2, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_IIC, + .paddr = IIC0_BASE, + .irq = IIC0_IRQ, + .pm = IBM_CPM_IIC0, + .additions = &ibmstb4_iic0_def, + .show = &ocp_show_iic_data + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_IIC, + .paddr = IIC1_BASE, + .irq = IIC1_IRQ, + .pm = IBM_CPM_IIC1, + .additions = &ibmstb4_iic1_def, + .show = &ocp_show_iic_data + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_GPIO, + .paddr = GPIO0_BASE, + .irq = OCP_IRQ_NA, + .pm = IBM_CPM_GPIO0, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_IDE, + .paddr = IDE0_BASE, + .irq = IDE0_IRQ, + .pm = OCP_CPM_NA, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_USB, + .paddr = USB0_BASE, + .irq = USB0_IRQ, + .pm = OCP_CPM_NA, + }, + { .vendor = OCP_VENDOR_INVALID, + } +}; diff --git a/arch/ppc/platforms/4xx/ibmstb4.h b/arch/ppc/platforms/4xx/ibmstb4.h new file mode 100644 index 00000000000..bcb4b1ee71f --- /dev/null +++ b/arch/ppc/platforms/4xx/ibmstb4.h @@ -0,0 +1,238 @@ +/* + * arch/ppc/platforms/4xx/ibmstb4.h + * + * Author: Armin Kuster <akuster@mvista.com> + * + * 2001 (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. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_IBMSTB4_H__ +#define __ASM_IBMSTB4_H__ + +#include <linux/config.h> + +/* serial port defines */ +#define STB04xxx_IO_BASE ((uint)0xe0000000) +#define PPC4xx_PCI_IO_ADDR STB04xxx_IO_BASE +#define PPC4xx_ONB_IO_PADDR STB04xxx_IO_BASE +#define PPC4xx_ONB_IO_VADDR ((uint)0xe0000000) +#define PPC4xx_ONB_IO_SIZE ((uint)14*64*1024) + +/* + * map STB04xxx internal i/o address (0x400x00xx) to an address + * which is below the 2GB limit... + * + * 4000 000x uart1 -> 0xe000 000x + * 4001 00xx ppu + * 4002 00xx smart card + * 4003 000x iic + * 4004 000x uart0 + * 4005 0xxx timer + * 4006 00xx gpio + * 4007 00xx smart card + * 400b 000x iic + * 400c 000x scp + * 400d 000x modem + * 400e 000x uart2 +*/ +#define STB04xxx_MAP_IO_ADDR(a) (((uint)(a)) + (STB04xxx_IO_BASE - 0x40000000)) + +#define RS_TABLE_SIZE 3 +#define UART0_INT 20 + +#ifdef __BOOTER__ +#define UART0_IO_BASE 0x40040000 +#else +#define UART0_IO_BASE 0xe0040000 +#endif + +#define UART1_INT 21 + +#ifdef __BOOTER__ +#define UART1_IO_BASE 0x40000000 +#else +#define UART1_IO_BASE 0xe0000000 +#endif + +#define UART2_INT 31 +#ifdef __BOOTER__ +#define UART2_IO_BASE 0x400e0000 +#else +#define UART2_IO_BASE 0xe00e0000 +#endif + +#define IDE0_BASE 0x400F0000 +#define IDE0_SIZE 0x200 +#define IDE0_IRQ 25 +#define IIC0_BASE 0x40030000 +#define IIC1_BASE 0x400b0000 +#define OPB0_BASE 0x40000000 +#define GPIO0_BASE 0x40060000 + +#define USB0_IRQ 18 +#define USB0_BASE STB04xxx_MAP_IO_ADDR(0x40010000) +#define USB0_EXTENT 4096 + +#define IIC_NUMS 2 +#define UART_NUMS 3 +#define IIC0_IRQ 9 +#define IIC1_IRQ 10 +#define IIC_OWN 0x55 +#define IIC_CLOCK 50 + +#define BD_EMAC_ADDR(e,i) bi_enetaddr[i] + +#define STD_UART_OP(num) \ + { 0, BASE_BAUD, 0, UART##num##_INT, \ + (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \ + iomem_base: (u8 *)UART##num##_IO_BASE, \ + io_type: SERIAL_IO_MEM}, + +#if defined(CONFIG_UART0_TTYS0) +#define SERIAL_DEBUG_IO_BASE UART0_IO_BASE +#define SERIAL_PORT_DFNS \ + STD_UART_OP(0) \ + STD_UART_OP(1) \ + STD_UART_OP(2) +#endif + +#if defined(CONFIG_UART0_TTYS1) +#define SERIAL_DEBUG_IO_BASE UART2_IO_BASE +#define SERIAL_PORT_DFNS \ + STD_UART_OP(1) \ + STD_UART_OP(0) \ + STD_UART_OP(2) +#endif + +#if defined(CONFIG_UART0_TTYS2) +#define SERIAL_DEBUG_IO_BASE UART2_IO_BASE +#define SERIAL_PORT_DFNS \ + STD_UART_OP(2) \ + STD_UART_OP(0) \ + STD_UART_OP(1) +#endif + +#define DCRN_BE_BASE 0x090 +#define DCRN_DMA0_BASE 0x0C0 +#define DCRN_DMA1_BASE 0x0C8 +#define DCRN_DMA2_BASE 0x0D0 +#define DCRN_DMA3_BASE 0x0D8 +#define DCRNCAP_DMA_CC 1 /* have DMA chained count capability */ +#define DCRN_DMASR_BASE 0x0E0 +#define DCRN_PLB0_BASE 0x054 +#define DCRN_PLB1_BASE 0x064 +#define DCRN_POB0_BASE 0x0B0 +#define DCRN_SCCR_BASE 0x120 +#define DCRN_UIC0_BASE 0x040 +#define DCRN_BE_BASE 0x090 +#define DCRN_DMA0_BASE 0x0C0 +#define DCRN_DMA1_BASE 0x0C8 +#define DCRN_DMA2_BASE 0x0D0 +#define DCRN_DMA3_BASE 0x0D8 +#define DCRN_CIC_BASE 0x030 +#define DCRN_DMASR_BASE 0x0E0 +#define DCRN_EBIMC_BASE 0x070 +#define DCRN_DCRX_BASE 0x020 +#define DCRN_CPMFR_BASE 0x102 +#define DCRN_SCCR_BASE 0x120 +#define UIC0 DCRN_UIC0_BASE + +#define IBM_CPM_IIC0 0x80000000 /* IIC 0 interface */ +#define IBM_CPM_USB0 0x40000000 /* IEEE-1284 */ +#define IBM_CPM_IIC1 0x20000000 /* IIC 1 interface */ +#define IBM_CPM_CPU 0x10000000 /* PPC405B3 clock control */ +#define IBM_CPM_AUD 0x08000000 /* Audio Decoder */ +#define IBM_CPM_EBIU 0x04000000 /* External Bus Interface Unit */ +#define IBM_CPM_SDRAM1 0x02000000 /* SDRAM 1 memory controller */ +#define IBM_CPM_DMA 0x01000000 /* DMA controller */ +#define IBM_CPM_DMA1 0x00800000 /* reserved */ +#define IBM_CPM_XPT1 0x00400000 /* reserved */ +#define IBM_CPM_XPT2 0x00200000 /* reserved */ +#define IBM_CPM_UART1 0x00100000 /* Serial 1 / Infrared */ +#define IBM_CPM_UART0 0x00080000 /* Serial 0 / 16550 */ +#define IBM_CPM_EPI 0x00040000 /* DCR Extension */ +#define IBM_CPM_SC0 0x00020000 /* Smart Card 0 */ +#define IBM_CPM_VID 0x00010000 /* reserved */ +#define IBM_CPM_SC1 0x00008000 /* Smart Card 1 */ +#define IBM_CPM_USBSDRA 0x00004000 /* SDRAM 0 memory controller */ +#define IBM_CPM_XPT0 0x00002000 /* Transport - 54 Mhz */ +#define IBM_CPM_CBS 0x00001000 /* Cross Bar Switch */ +#define IBM_CPM_GPT 0x00000800 /* GPTPWM */ +#define IBM_CPM_GPIO0 0x00000400 /* General Purpose IO 0 */ +#define IBM_CPM_DENC 0x00000200 /* Digital video Encoder */ +#define IBM_CPM_TMRCLK 0x00000100 /* CPU timers */ +#define IBM_CPM_XPT27 0x00000080 /* Transport - 27 Mhz */ +#define IBM_CPM_UIC 0x00000040 /* Universal Interrupt Controller */ +#define IBM_CPM_SSP 0x00000010 /* Modem Serial Interface (SSP) */ +#define IBM_CPM_UART2 0x00000008 /* Serial Control Port */ +#define IBM_CPM_DDIO 0x00000004 /* Descrambler */ +#define IBM_CPM_VID2 0x00000002 /* Video Decoder clock domain 2 */ + +#define DFLT_IBM4xx_PM ~(IBM_CPM_CPU | IBM_CPM_EBIU | IBM_CPM_SDRAM1 \ + | IBM_CPM_DMA | IBM_CPM_DMA1 | IBM_CPM_CBS \ + | IBM_CPM_USBSDRA | IBM_CPM_XPT0 | IBM_CPM_TMRCLK \ + | IBM_CPM_XPT27 | IBM_CPM_UIC ) + +#define DCRN_BEAR (DCRN_BE_BASE + 0x0) /* Bus Error Address Register */ +#define DCRN_BESR (DCRN_BE_BASE + 0x1) /* Bus Error Syndrome Register */ +/* DCRN_BESR */ +#define BESR_DSES 0x80000000 /* Data-Side Error Status */ +#define BESR_DMES 0x40000000 /* DMA Error Status */ +#define BESR_RWS 0x20000000 /* Read/Write Status */ +#define BESR_ETMASK 0x1C000000 /* Error Type */ +#define ET_PROT 0 +#define ET_PARITY 1 +#define ET_NCFG 2 +#define ET_BUSERR 4 +#define ET_BUSTO 6 + +#define CHR1_CETE 0x00800000 /* CPU external timer enable */ +#define CHR1_PCIPW 0x00008000 /* PCI Int enable/Peripheral Write enable */ + +#define DCRN_CICCR (DCRN_CIC_BASE + 0x0) /* CIC Control Register */ +#define DCRN_DMAS1 (DCRN_CIC_BASE + 0x1) /* DMA Select1 Register */ +#define DCRN_DMAS2 (DCRN_CIC_BASE + 0x2) /* DMA Select2 Register */ +#define DCRN_CICVCR (DCRN_CIC_BASE + 0x3) /* CIC Video COntro Register */ +#define DCRN_CICSEL3 (DCRN_CIC_BASE + 0x5) /* CIC Select 3 Register */ +#define DCRN_SGPO (DCRN_CIC_BASE + 0x6) /* CIC GPIO Output Register */ +#define DCRN_SGPOD (DCRN_CIC_BASE + 0x7) /* CIC GPIO OD Register */ +#define DCRN_SGPTC (DCRN_CIC_BASE + 0x8) /* CIC GPIO Tristate Ctrl Reg */ +#define DCRN_SGPI (DCRN_CIC_BASE + 0x9) /* CIC GPIO Input Reg */ + +#define DCRN_DCRXICR (DCRN_DCRX_BASE + 0x0) /* Internal Control Register */ +#define DCRN_DCRXISR (DCRN_DCRX_BASE + 0x1) /* Internal Status Register */ +#define DCRN_DCRXECR (DCRN_DCRX_BASE + 0x2) /* External Control Register */ +#define DCRN_DCRXESR (DCRN_DCRX_BASE + 0x3) /* External Status Register */ +#define DCRN_DCRXTAR (DCRN_DCRX_BASE + 0x4) /* Target Address Register */ +#define DCRN_DCRXTDR (DCRN_DCRX_BASE + 0x5) /* Target Data Register */ +#define DCRN_DCRXIGR (DCRN_DCRX_BASE + 0x6) /* Interrupt Generation Register */ +#define DCRN_DCRXBCR (DCRN_DCRX_BASE + 0x7) /* Line Buffer Control Register */ + +#define DCRN_BRCRH0 (DCRN_EBIMC_BASE + 0x0) /* Bus Region Config High 0 */ +#define DCRN_BRCRH1 (DCRN_EBIMC_BASE + 0x1) /* Bus Region Config High 1 */ +#define DCRN_BRCRH2 (DCRN_EBIMC_BASE + 0x2) /* Bus Region Config High 2 */ +#define DCRN_BRCRH3 (DCRN_EBIMC_BASE + 0x3) /* Bus Region Config High 3 */ +#define DCRN_BRCRH4 (DCRN_EBIMC_BASE + 0x4) /* Bus Region Config High 4 */ +#define DCRN_BRCRH5 (DCRN_EBIMC_BASE + 0x5) /* Bus Region Config High 5 */ +#define DCRN_BRCRH6 (DCRN_EBIMC_BASE + 0x6) /* Bus Region Config High 6 */ +#define DCRN_BRCRH7 (DCRN_EBIMC_BASE + 0x7) /* Bus Region Config High 7 */ +#define DCRN_BRCR0 (DCRN_EBIMC_BASE + 0x10) /* BRC 0 */ +#define DCRN_BRCR1 (DCRN_EBIMC_BASE + 0x11) /* BRC 1 */ +#define DCRN_BRCR2 (DCRN_EBIMC_BASE + 0x12) /* BRC 2 */ +#define DCRN_BRCR3 (DCRN_EBIMC_BASE + 0x13) /* BRC 3 */ +#define DCRN_BRCR4 (DCRN_EBIMC_BASE + 0x14) /* BRC 4 */ +#define DCRN_BRCR5 (DCRN_EBIMC_BASE + 0x15) /* BRC 5 */ +#define DCRN_BRCR6 (DCRN_EBIMC_BASE + 0x16) /* BRC 6 */ +#define DCRN_BRCR7 (DCRN_EBIMC_BASE + 0x17) /* BRC 7 */ +#define DCRN_BEAR0 (DCRN_EBIMC_BASE + 0x20) /* Bus Error Address Register */ +#define DCRN_BESR0 (DCRN_EBIMC_BASE + 0x21) /* Bus Error Status Register */ +#define DCRN_BIUCR (DCRN_EBIMC_BASE + 0x2A) /* Bus Interfac Unit Ctrl Reg */ + +#include <asm/ibm405.h> + +#endif /* __ASM_IBMSTB4_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/ibmstbx25.c b/arch/ppc/platforms/4xx/ibmstbx25.c new file mode 100644 index 00000000000..b895b9cca57 --- /dev/null +++ b/arch/ppc/platforms/4xx/ibmstbx25.c @@ -0,0 +1,68 @@ +/* + * arch/ppc/platforms/4xx/ibmstbx25.c + * + * Author: Armin Kuster <akuster@mvista.com> + * + * 2000-2002 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include <linux/init.h> +#include <asm/ocp.h> +#include <platforms/4xx/ibmstbx25.h> +#include <asm/ppc4xx_pic.h> + +static struct ocp_func_iic_data ibmstbx25_iic0_def = { + .fast_mode = 0, /* Use standad mode (100Khz) */ +}; +OCP_SYSFS_IIC_DATA() + +struct ocp_def core_ocp[] __initdata = { + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 0, + .paddr = UART0_IO_BASE, + .irq = UART0_INT, + .pm = IBM_CPM_UART0, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 1, + .paddr = UART1_IO_BASE, + .irq = UART1_INT, + .pm = IBM_CPM_UART1, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 2, + .paddr = UART2_IO_BASE, + .irq = UART2_INT, + .pm = IBM_CPM_UART2, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_IIC, + .paddr = IIC0_BASE, + .irq = IIC0_IRQ, + .pm = IBM_CPM_IIC0, + .additions = &ibmstbx25_iic0_def, + .show = &ocp_show_iic_data + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_GPIO, + .paddr = GPIO0_BASE, + .irq = OCP_IRQ_NA, + .pm = IBM_CPM_GPIO0, + }, + { .vendor = OCP_VENDOR_INVALID + } +}; + +/* Polarity and triggering settings for internal interrupt sources */ +struct ppc4xx_uic_settings ppc4xx_core_uic_cfg[] __initdata = { + { .polarity = 0xffff8f80, + .triggering = 0x00000000, + .ext_irq_mask = 0x0000707f, /* IRQ7 - IRQ9, IRQ0 - IRQ6 */ + } +}; diff --git a/arch/ppc/platforms/4xx/ibmstbx25.h b/arch/ppc/platforms/4xx/ibmstbx25.h new file mode 100644 index 00000000000..9a2efc366e9 --- /dev/null +++ b/arch/ppc/platforms/4xx/ibmstbx25.h @@ -0,0 +1,261 @@ +/* + * arch/ppc/platforms/4xx/ibmstbx25.h + * + * Author: Armin Kuster <akuster@mvista.com> + * + * 2002 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_IBMSTBX25_H__ +#define __ASM_IBMSTBX25_H__ + +#include <linux/config.h> + +/* serial port defines */ +#define STBx25xx_IO_BASE ((uint)0xe0000000) +#define PPC4xx_ONB_IO_PADDR STBx25xx_IO_BASE +#define PPC4xx_ONB_IO_VADDR ((uint)0xe0000000) +#define PPC4xx_ONB_IO_SIZE ((uint)14*64*1024) + +/* + * map STBxxxx internal i/o address (0x400x00xx) to an address + * which is below the 2GB limit... + * + * 4000 000x uart1 -> 0xe000 000x + * 4001 00xx uart2 + * 4002 00xx smart card + * 4003 000x iic + * 4004 000x uart0 + * 4005 0xxx timer + * 4006 00xx gpio + * 4007 00xx smart card + * 400b 000x iic + * 400c 000x scp + * 400d 000x modem + * 400e 000x uart2 +*/ +#define STBx25xx_MAP_IO_ADDR(a) (((uint)(a)) + (STBx25xx_IO_BASE - 0x40000000)) + +#define RS_TABLE_SIZE 3 + +#define OPB_BASE_START 0x40000000 +#define EBIU_BASE_START 0xF0100000 +#define DCR_BASE_START 0x0000 + +#ifdef __BOOTER__ +#define UART1_IO_BASE 0x40000000 +#define UART2_IO_BASE 0x40010000 +#else +#define UART1_IO_BASE 0xe0000000 +#define UART2_IO_BASE 0xe0010000 +#endif +#define SC0_BASE 0x40020000 /* smart card #0 */ +#define IIC0_BASE 0x40030000 +#ifdef __BOOTER__ +#define UART0_IO_BASE 0x40040000 +#else +#define UART0_IO_BASE 0xe0040000 +#endif +#define SCC0_BASE 0x40040000 /* Serial 0 controller IrdA */ +#define GPT0_BASE 0x40050000 /* General purpose timers */ +#define GPIO0_BASE 0x40060000 +#define SC1_BASE 0x40070000 /* smart card #1 */ +#define SCP0_BASE 0x400C0000 /* Serial Controller Port */ +#define SSP0_BASE 0x400D0000 /* Sync serial port */ + +#define IDE0_BASE 0xf0100000 +#define REDWOOD_IDE_CTRL 0xf1100000 + +#define RTCFPC_IRQ 0 +#define XPORT_IRQ 1 +#define AUD_IRQ 2 +#define AID_IRQ 3 +#define DMA0 4 +#define DMA1_IRQ 5 +#define DMA2_IRQ 6 +#define DMA3_IRQ 7 +#define SC0_IRQ 8 +#define IIC0_IRQ 9 +#define IIR0_IRQ 10 +#define GPT0_IRQ 11 +#define GPT1_IRQ 12 +#define SCP0_IRQ 13 +#define SSP0_IRQ 14 +#define GPT2_IRQ 15 /* count down timer */ +#define SC1_IRQ 16 +/* IRQ 17 - 19 external */ +#define UART0_INT 20 +#define UART1_INT 21 +#define UART2_INT 22 +#define XPTDMA_IRQ 23 +#define DCRIDE_IRQ 24 +/* IRQ 25 - 30 external */ +#define IDE0_IRQ 26 + +#define IIC_NUMS 1 +#define UART_NUMS 3 +#define IIC_OWN 0x55 +#define IIC_CLOCK 50 + +#define BD_EMAC_ADDR(e,i) bi_enetaddr[i] + +#define STD_UART_OP(num) \ + { 0, BASE_BAUD, 0, UART##num##_INT, \ + (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \ + iomem_base: (u8 *)UART##num##_IO_BASE, \ + io_type: SERIAL_IO_MEM}, + +#if defined(CONFIG_UART0_TTYS0) +#define SERIAL_DEBUG_IO_BASE UART0_IO_BASE +#define SERIAL_PORT_DFNS \ + STD_UART_OP(0) \ + STD_UART_OP(1) \ + STD_UART_OP(2) +#endif + +#if defined(CONFIG_UART0_TTYS1) +#define SERIAL_DEBUG_IO_BASE UART2_IO_BASE +#define SERIAL_PORT_DFNS \ + STD_UART_OP(1) \ + STD_UART_OP(0) \ + STD_UART_OP(2) +#endif + +#if defined(CONFIG_UART0_TTYS2) +#define SERIAL_DEBUG_IO_BASE UART2_IO_BASE +#define SERIAL_PORT_DFNS \ + STD_UART_OP(2) \ + STD_UART_OP(0) \ + STD_UART_OP(1) +#endif + +#define DCRN_BE_BASE 0x090 +#define DCRN_DMA0_BASE 0x0C0 +#define DCRN_DMA1_BASE 0x0C8 +#define DCRN_DMA2_BASE 0x0D0 +#define DCRN_DMA3_BASE 0x0D8 +#define DCRNCAP_DMA_CC 1 /* have DMA chained count capability */ +#define DCRN_DMASR_BASE 0x0E0 +#define DCRN_PLB0_BASE 0x054 +#define DCRN_PLB1_BASE 0x064 +#define DCRN_POB0_BASE 0x0B0 +#define DCRN_SCCR_BASE 0x120 +#define DCRN_UIC0_BASE 0x040 +#define DCRN_BE_BASE 0x090 +#define DCRN_DMA0_BASE 0x0C0 +#define DCRN_DMA1_BASE 0x0C8 +#define DCRN_DMA2_BASE 0x0D0 +#define DCRN_DMA3_BASE 0x0D8 +#define DCRN_CIC_BASE 0x030 +#define DCRN_DMASR_BASE 0x0E0 +#define DCRN_EBIMC_BASE 0x070 +#define DCRN_DCRX_BASE 0x020 +#define DCRN_CPMFR_BASE 0x102 +#define DCRN_SCCR_BASE 0x120 +#define DCRN_RTCFP_BASE 0x310 + +#define UIC0 DCRN_UIC0_BASE + +#define IBM_CPM_IIC0 0x80000000 /* IIC 0 interface */ +#define IBM_CPM_CPU 0x10000000 /* PPC405B3 clock control */ +#define IBM_CPM_AUD 0x08000000 /* Audio Decoder */ +#define IBM_CPM_EBIU 0x04000000 /* External Bus Interface Unit */ +#define IBM_CPM_IRR 0x02000000 /* Infrared receiver */ +#define IBM_CPM_DMA 0x01000000 /* DMA controller */ +#define IBM_CPM_UART2 0x00200000 /* Serial Control Port */ +#define IBM_CPM_UART1 0x00100000 /* Serial 1 / Infrared */ +#define IBM_CPM_UART0 0x00080000 /* Serial 0 / 16550 */ +#define IBM_PM_DCRIDE 0x00040000 /* DCR timeout & IDE line Mode clock */ +#define IBM_CPM_SC0 0x00020000 /* Smart Card 0 */ +#define IBM_CPM_VID 0x00010000 /* reserved */ +#define IBM_CPM_SC1 0x00008000 /* Smart Card 0 */ +#define IBM_CPM_XPT0 0x00002000 /* Transport - 54 Mhz */ +#define IBM_CPM_CBS 0x00001000 /* Cross Bar Switch */ +#define IBM_CPM_GPT 0x00000800 /* GPTPWM */ +#define IBM_CPM_GPIO0 0x00000400 /* General Purpose IO 0 */ +#define IBM_CPM_DENC 0x00000200 /* Digital video Encoder */ +#define IBM_CPM_C405T 0x00000100 /* CPU timers */ +#define IBM_CPM_XPT27 0x00000080 /* Transport - 27 Mhz */ +#define IBM_CPM_UIC 0x00000040 /* Universal Interrupt Controller */ +#define IBM_CPM_RTCFPC 0x00000020 /* Realtime clock and front panel */ +#define IBM_CPM_SSP 0x00000010 /* Modem Serial Interface (SSP) */ +#define IBM_CPM_VID2 0x00000002 /* Video Decoder clock domain 2 */ +#define DFLT_IBM4xx_PM ~(IBM_CPM_CPU | IBM_CPM_EBIU | IBM_CPM_DMA \ + | IBM_CPM_CBS | IBM_CPM_XPT0 | IBM_CPM_C405T \ + | IBM_CPM_XPT27 | IBM_CPM_UIC) + +#define DCRN_BEAR (DCRN_BE_BASE + 0x0) /* Bus Error Address Register */ +#define DCRN_BESR (DCRN_BE_BASE + 0x1) /* Bus Error Syndrome Register */ +/* DCRN_BESR */ +#define BESR_DSES 0x80000000 /* Data-Side Error Status */ +#define BESR_DMES 0x40000000 /* DMA Error Status */ +#define BESR_RWS 0x20000000 /* Read/Write Status */ +#define BESR_ETMASK 0x1C000000 /* Error Type */ +#define ET_PROT 0 +#define ET_PARITY 1 +#define ET_NCFG 2 +#define ET_BUSERR 4 +#define ET_BUSTO 6 + +#define CHR1_CETE 0x00800000 /* CPU external timer enable */ +#define CHR1_PCIPW 0x00008000 /* PCI Int enable/Peripheral Write enable */ + +#define DCRN_CICCR (DCRN_CIC_BASE + 0x0) /* CIC Control Register */ +#define DCRN_DMAS1 (DCRN_CIC_BASE + 0x1) /* DMA Select1 Register */ +#define DCRN_DMAS2 (DCRN_CIC_BASE + 0x2) /* DMA Select2 Register */ +#define DCRN_CICVCR (DCRN_CIC_BASE + 0x3) /* CIC Video COntro Register */ +#define DCRN_CICSEL3 (DCRN_CIC_BASE + 0x5) /* CIC Select 3 Register */ +#define DCRN_SGPO (DCRN_CIC_BASE + 0x6) /* CIC GPIO Output Register */ +#define DCRN_SGPOD (DCRN_CIC_BASE + 0x7) /* CIC GPIO OD Register */ +#define DCRN_SGPTC (DCRN_CIC_BASE + 0x8) /* CIC GPIO Tristate Ctrl Reg */ +#define DCRN_SGPI (DCRN_CIC_BASE + 0x9) /* CIC GPIO Input Reg */ + +#define DCRN_DCRXICR (DCRN_DCRX_BASE + 0x0) /* Internal Control Register */ +#define DCRN_DCRXISR (DCRN_DCRX_BASE + 0x1) /* Internal Status Register */ +#define DCRN_DCRXECR (DCRN_DCRX_BASE + 0x2) /* External Control Register */ +#define DCRN_DCRXESR (DCRN_DCRX_BASE + 0x3) /* External Status Register */ +#define DCRN_DCRXTAR (DCRN_DCRX_BASE + 0x4) /* Target Address Register */ +#define DCRN_DCRXTDR (DCRN_DCRX_BASE + 0x5) /* Target Data Register */ +#define DCRN_DCRXIGR (DCRN_DCRX_BASE + 0x6) /* Interrupt Generation Register */ +#define DCRN_DCRXBCR (DCRN_DCRX_BASE + 0x7) /* Line Buffer Control Register */ + +#define DCRN_BRCRH0 (DCRN_EBIMC_BASE + 0x0) /* Bus Region Config High 0 */ +#define DCRN_BRCRH1 (DCRN_EBIMC_BASE + 0x1) /* Bus Region Config High 1 */ +#define DCRN_BRCRH2 (DCRN_EBIMC_BASE + 0x2) /* Bus Region Config High 2 */ +#define DCRN_BRCRH3 (DCRN_EBIMC_BASE + 0x3) /* Bus Region Config High 3 */ +#define DCRN_BRCRH4 (DCRN_EBIMC_BASE + 0x4) /* Bus Region Config High 4 */ +#define DCRN_BRCRH5 (DCRN_EBIMC_BASE + 0x5) /* Bus Region Config High 5 */ +#define DCRN_BRCRH6 (DCRN_EBIMC_BASE + 0x6) /* Bus Region Config High 6 */ +#define DCRN_BRCRH7 (DCRN_EBIMC_BASE + 0x7) /* Bus Region Config High 7 */ +#define DCRN_BRCR0 (DCRN_EBIMC_BASE + 0x10) /* BRC 0 */ +#define DCRN_BRCR1 (DCRN_EBIMC_BASE + 0x11) /* BRC 1 */ +#define DCRN_BRCR2 (DCRN_EBIMC_BASE + 0x12) /* BRC 2 */ +#define DCRN_BRCR3 (DCRN_EBIMC_BASE + 0x13) /* BRC 3 */ +#define DCRN_BRCR4 (DCRN_EBIMC_BASE + 0x14) /* BRC 4 */ +#define DCRN_BRCR5 (DCRN_EBIMC_BASE + 0x15) /* BRC 5 */ +#define DCRN_BRCR6 (DCRN_EBIMC_BASE + 0x16) /* BRC 6 */ +#define DCRN_BRCR7 (DCRN_EBIMC_BASE + 0x17) /* BRC 7 */ +#define DCRN_BEAR0 (DCRN_EBIMC_BASE + 0x20) /* Bus Error Address Register */ +#define DCRN_BESR0 (DCRN_EBIMC_BASE + 0x21) /* Bus Error Status Register */ +#define DCRN_BIUCR (DCRN_EBIMC_BASE + 0x2A) /* Bus Interfac Unit Ctrl Reg */ + +#define DCRN_RTC_FPC0_CNTL (DCRN_RTCFP_BASE + 0x00) /* RTC cntl */ +#define DCRN_RTC_FPC0_INT (DCRN_RTCFP_BASE + 0x01) /* RTC Interrupt */ +#define DCRN_RTC_FPC0_TIME (DCRN_RTCFP_BASE + 0x02) /* RTC time reg */ +#define DCRN_RTC_FPC0_ALRM (DCRN_RTCFP_BASE + 0x03) /* RTC Alarm reg */ +#define DCRN_RTC_FPC0_D1 (DCRN_RTCFP_BASE + 0x04) /* LED Data 1 */ +#define DCRN_RTC_FPC0_D2 (DCRN_RTCFP_BASE + 0x05) /* LED Data 2 */ +#define DCRN_RTC_FPC0_D3 (DCRN_RTCFP_BASE + 0x06) /* LED Data 3 */ +#define DCRN_RTC_FPC0_D4 (DCRN_RTCFP_BASE + 0x07) /* LED Data 4 */ +#define DCRN_RTC_FPC0_D5 (DCRN_RTCFP_BASE + 0x08) /* LED Data 5 */ +#define DCRN_RTC_FPC0_FCNTL (DCRN_RTCFP_BASE + 0x09) /* LED control */ +#define DCRN_RTC_FPC0_BRT (DCRN_RTCFP_BASE + 0x0A) /* Brightness cntl */ + +#include <asm/ibm405.h> + +#endif /* __ASM_IBMSTBX25_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/luan.c b/arch/ppc/platforms/4xx/luan.c new file mode 100644 index 00000000000..1df2339f1f6 --- /dev/null +++ b/arch/ppc/platforms/4xx/luan.c @@ -0,0 +1,387 @@ +/* + * arch/ppc/platforms/4xx/luan.c + * + * Luan board specific routines + * + * Matt Porter <mporter@kernel.crashing.org> + * + * Copyright 2004-2005 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/types.h> +#include <linux/major.h> +#include <linux/blkdev.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/ide.h> +#include <linux/initrd.h> +#include <linux/irq.h> +#include <linux/seq_file.h> +#include <linux/root_dev.h> +#include <linux/tty.h> +#include <linux/serial.h> +#include <linux/serial_core.h> + +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/machdep.h> +#include <asm/ocp.h> +#include <asm/pci-bridge.h> +#include <asm/time.h> +#include <asm/todc.h> +#include <asm/bootinfo.h> +#include <asm/ppc4xx_pic.h> +#include <asm/ppcboot.h> + +#include <syslib/ibm44x_common.h> +#include <syslib/ibm440gx_common.h> +#include <syslib/ibm440sp_common.h> + +/* + * This is a horrible kludge, we eventually need to abstract this + * generic PHY stuff, so the standard phy mode defines can be + * easily used from arch code. + */ +#include "../../../../drivers/net/ibm_emac/ibm_emac_phy.h" + +bd_t __res; + +static struct ibm44x_clocks clocks __initdata; + +static void __init +luan_calibrate_decr(void) +{ + unsigned int freq; + + if (mfspr(SPRN_CCR1) & CCR1_TCS) + freq = LUAN_TMR_CLK; + else + freq = clocks.cpu; + + ibm44x_calibrate_decr(freq); +} + +static int +luan_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "vendor\t\t: IBM\n"); + seq_printf(m, "machine\t\t: PPC440SP EVB (Luan)\n"); + + return 0; +} + +static inline int +luan_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); + + /* PCIX0 in adapter mode, no host interrupt routing */ + + /* PCIX1 */ + if (hose->index == 0) { + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + { 49, 49, 49, 49 }, /* IDSEL 1 - PCIX1 Slot 0 */ + { 49, 49, 49, 49 }, /* IDSEL 2 - PCIX1 Slot 1 */ + { 49, 49, 49, 49 }, /* IDSEL 3 - PCIX1 Slot 2 */ + { 49, 49, 49, 49 }, /* IDSEL 4 - PCIX1 Slot 3 */ + }; + const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; + /* PCIX2 */ + } else if (hose->index == 1) { + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + { 50, 50, 50, 50 }, /* IDSEL 1 - PCIX2 Slot 0 */ + { 50, 50, 50, 50 }, /* IDSEL 2 - PCIX2 Slot 1 */ + { 50, 50, 50, 50 }, /* IDSEL 3 - PCIX2 Slot 2 */ + { 50, 50, 50, 50 }, /* IDSEL 4 - PCIX2 Slot 3 */ + }; + const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; + } + return -1; +} + +static void __init luan_set_emacdata(void) +{ + struct ocp_def *def; + struct ocp_func_emac_data *emacdata; + + /* Set phy_map, phy_mode, and mac_addr for the EMAC */ + def = ocp_get_one_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, 0); + emacdata = def->additions; + emacdata->phy_map = 0x00000001; /* Skip 0x00 */ + emacdata->phy_mode = PHY_MODE_GMII; + memcpy(emacdata->mac_addr, __res.bi_enetaddr, 6); +} + +#define PCIX_READW(offset) \ + (readw((void *)((u32)pcix_reg_base+offset))) + +#define PCIX_WRITEW(value, offset) \ + (writew(value, (void *)((u32)pcix_reg_base+offset))) + +#define PCIX_WRITEL(value, offset) \ + (writel(value, (void *)((u32)pcix_reg_base+offset))) + +static void __init +luan_setup_pcix(void) +{ + int i; + void *pcix_reg_base; + + for (i=0;i<3;i++) { + pcix_reg_base = ioremap64(PCIX0_REG_BASE + i*PCIX_REG_OFFSET, PCIX_REG_SIZE); + + /* Enable PCIX0 I/O, Mem, and Busmaster cycles */ + PCIX_WRITEW(PCIX_READW(PCIX0_COMMAND) | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, PCIX0_COMMAND); + + /* Disable all windows */ + PCIX_WRITEL(0, PCIX0_POM0SA); + PCIX_WRITEL(0, PCIX0_POM1SA); + PCIX_WRITEL(0, PCIX0_POM2SA); + PCIX_WRITEL(0, PCIX0_PIM0SA); + PCIX_WRITEL(0, PCIX0_PIM0SAH); + PCIX_WRITEL(0, PCIX0_PIM1SA); + PCIX_WRITEL(0, PCIX0_PIM2SA); + PCIX_WRITEL(0, PCIX0_PIM2SAH); + + /* + * Setup 512MB PLB->PCI outbound mem window + * (a_n000_0000->0_n000_0000) + * */ + PCIX_WRITEL(0x0000000a, PCIX0_POM0LAH); + PCIX_WRITEL(0x80000000 | i*LUAN_PCIX_MEM_SIZE, PCIX0_POM0LAL); + PCIX_WRITEL(0x00000000, PCIX0_POM0PCIAH); + PCIX_WRITEL(0x80000000 | i*LUAN_PCIX_MEM_SIZE, PCIX0_POM0PCIAL); + PCIX_WRITEL(0xe0000001, PCIX0_POM0SA); + + /* Setup 2GB PCI->PLB inbound memory window at 0, enable MSIs */ + PCIX_WRITEL(0x00000000, PCIX0_PIM0LAH); + PCIX_WRITEL(0x00000000, PCIX0_PIM0LAL); + PCIX_WRITEL(0xe0000007, PCIX0_PIM0SA); + PCIX_WRITEL(0xffffffff, PCIX0_PIM0SAH); + + iounmap(pcix_reg_base); + } + + eieio(); +} + +static void __init +luan_setup_hose(struct pci_controller *hose, + int lower_mem, + int upper_mem, + int cfga, + int cfgd, + u64 pcix_io_base) +{ + char name[20]; + + sprintf(name, "PCIX%d host bridge", hose->index); + + hose->pci_mem_offset = LUAN_PCIX_MEM_OFFSET; + + pci_init_resource(&hose->io_resource, + LUAN_PCIX_LOWER_IO, + LUAN_PCIX_UPPER_IO, + IORESOURCE_IO, + name); + + pci_init_resource(&hose->mem_resources[0], + lower_mem, + upper_mem, + IORESOURCE_MEM, + name); + + hose->io_space.start = LUAN_PCIX_LOWER_IO; + hose->io_space.end = LUAN_PCIX_UPPER_IO; + hose->mem_space.start = lower_mem; + hose->mem_space.end = upper_mem; + isa_io_base = + (unsigned long)ioremap64(pcix_io_base, PCIX_IO_SIZE); + hose->io_base_virt = (void *)isa_io_base; + + setup_indirect_pci(hose, cfga, cfgd); + hose->set_cfg_type = 1; +} + +static void __init +luan_setup_hoses(void) +{ + struct pci_controller *hose1, *hose2; + + /* Configure windows on the PCI-X host bridge */ + luan_setup_pcix(); + + /* Allocate hoses for PCIX1 and PCIX2 */ + hose1 = pcibios_alloc_controller(); + hose2 = pcibios_alloc_controller(); + if (!hose1 || !hose2) + return; + + /* Setup PCIX1 */ + hose1->first_busno = 0; + hose1->last_busno = 0xff; + + luan_setup_hose(hose1, + LUAN_PCIX1_LOWER_MEM, + LUAN_PCIX1_UPPER_MEM, + PCIX1_CFGA, + PCIX1_CFGD, + PCIX1_IO_BASE); + + hose1->last_busno = pciauto_bus_scan(hose1, hose1->first_busno); + + /* Setup PCIX2 */ + hose2->first_busno = hose1->last_busno + 1; + hose2->last_busno = 0xff; + + luan_setup_hose(hose2, + LUAN_PCIX2_LOWER_MEM, + LUAN_PCIX2_UPPER_MEM, + PCIX2_CFGA, + PCIX2_CFGD, + PCIX2_IO_BASE); + + hose2->last_busno = pciauto_bus_scan(hose2, hose2->first_busno); + + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = luan_map_irq; +} + +TODC_ALLOC(); + +static void __init +luan_early_serial_map(void) +{ + struct uart_port port; + + /* Setup ioremapped serial port access */ + memset(&port, 0, sizeof(port)); + port.membase = ioremap64(PPC440SP_UART0_ADDR, 8); + port.irq = UART0_INT; + port.uartclk = clocks.uart0; + port.regshift = 0; + port.iotype = SERIAL_IO_MEM; + port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST; + port.line = 0; + + if (early_serial_setup(&port) != 0) { + printk("Early serial init of port 0 failed\n"); + } + + port.membase = ioremap64(PPC440SP_UART1_ADDR, 8); + port.irq = UART1_INT; + port.uartclk = clocks.uart1; + port.line = 1; + + if (early_serial_setup(&port) != 0) { + printk("Early serial init of port 1 failed\n"); + } + + port.membase = ioremap64(PPC440SP_UART2_ADDR, 8); + port.irq = UART2_INT; + port.uartclk = BASE_BAUD; + port.line = 2; + + if (early_serial_setup(&port) != 0) { + printk("Early serial init of port 2 failed\n"); + } +} + +static void __init +luan_setup_arch(void) +{ + luan_set_emacdata(); + +#if !defined(CONFIG_BDI_SWITCH) + /* + * The Abatron BDI JTAG debugger does not tolerate others + * mucking with the debug registers. + */ + mtspr(SPRN_DBCR0, (DBCR0_TDE | DBCR0_IDM)); +#endif + + /* + * Determine various clocks. + * To be completely correct we should get SysClk + * from FPGA, because it can be changed by on-board switches + * --ebs + */ + /* 440GX and 440SP clocking is the same -mdp */ + ibm440gx_get_clocks(&clocks, 33333333, 6 * 1843200); + ocp_sys_info.opb_bus_freq = clocks.opb; + + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000/HZ; + + /* Setup PCIXn host bridges */ + luan_setup_hoses(); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_HDA1; +#endif + + luan_early_serial_map(); + + /* Identify the system */ + printk("Luan port (MontaVista Software, Inc. <source@mvista.com>)\n"); +} + +void __init platform_init(unsigned long r3, unsigned long r4, + unsigned long r5, unsigned long r6, unsigned long r7) +{ + parse_bootinfo(find_bootinfo()); + + /* + * If we were passed in a board information, copy it into the + * residual data area. + */ + if (r3) + __res = *(bd_t *)(r3 + KERNELBASE); + + ibm44x_platform_init(); + + ppc_md.setup_arch = luan_setup_arch; + ppc_md.show_cpuinfo = luan_show_cpuinfo; + ppc_md.find_end_of_memory = ibm440sp_find_end_of_memory; + ppc_md.get_irq = NULL; /* Set in ppc4xx_pic_init() */ + + ppc_md.calibrate_decr = luan_calibrate_decr; +#ifdef CONFIG_KGDB + ppc_md.early_serial_map = luan_early_serial_map; +#endif +} diff --git a/arch/ppc/platforms/4xx/luan.h b/arch/ppc/platforms/4xx/luan.h new file mode 100644 index 00000000000..09b444c8781 --- /dev/null +++ b/arch/ppc/platforms/4xx/luan.h @@ -0,0 +1,80 @@ +/* + * arch/ppc/platforms/4xx/luan.h + * + * Luan board definitions + * + * Matt Porter <mporter@kernel.crashing.org> + * + * Copyright 2004-2005 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifdef __KERNEL__ +#ifndef __ASM_LUAN_H__ +#define __ASM_LUAN_H__ + +#include <linux/config.h> +#include <platforms/4xx/ibm440sp.h> + +/* F/W TLB mapping used in bootloader glue to reset EMAC */ +#define PPC44x_EMAC0_MR0 0xa0000800 + +/* Location of MAC addresses in PIBS image */ +#define PIBS_FLASH_BASE 0xffe00000 +#define PIBS_MAC_BASE (PIBS_FLASH_BASE+0x1b0400) + +/* External timer clock frequency */ +#define LUAN_TMR_CLK 25000000 + +/* Flash */ +#define LUAN_FPGA_REG_0 0x0000000148300000ULL +#define LUAN_BOOT_LARGE_FLASH(x) (x & 0x40) +#define LUAN_SMALL_FLASH_LOW 0x00000001ff900000ULL +#define LUAN_SMALL_FLASH_HIGH 0x00000001ffe00000ULL +#define LUAN_SMALL_FLASH_SIZE 0x100000 +#define LUAN_LARGE_FLASH_LOW 0x00000001ff800000ULL +#define LUAN_LARGE_FLASH_HIGH 0x00000001ffc00000ULL +#define LUAN_LARGE_FLASH_SIZE 0x400000 + +/* + * Serial port defines + */ +#define RS_TABLE_SIZE 3 + +/* PIBS defined UART mappings, used before early_serial_setup */ +#define UART0_IO_BASE 0xa0000200 +#define UART1_IO_BASE 0xa0000300 +#define UART2_IO_BASE 0xa0000600 + +#define BASE_BAUD 11059200 +#define STD_UART_OP(num) \ + { 0, BASE_BAUD, 0, UART##num##_INT, \ + (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \ + iomem_base: UART##num##_IO_BASE, \ + io_type: SERIAL_IO_MEM}, + +#define SERIAL_PORT_DFNS \ + STD_UART_OP(0) \ + STD_UART_OP(1) \ + STD_UART_OP(2) + +/* PCI support */ +#define LUAN_PCIX_LOWER_IO 0x00000000 +#define LUAN_PCIX_UPPER_IO 0x0000ffff +#define LUAN_PCIX0_LOWER_MEM 0x80000000 +#define LUAN_PCIX0_UPPER_MEM 0x9fffffff +#define LUAN_PCIX1_LOWER_MEM 0xa0000000 +#define LUAN_PCIX1_UPPER_MEM 0xbfffffff +#define LUAN_PCIX2_LOWER_MEM 0xc0000000 +#define LUAN_PCIX2_UPPER_MEM 0xdfffffff + +#define LUAN_PCIX_MEM_SIZE 0x20000000 +#define LUAN_PCIX_MEM_OFFSET 0x00000000 + +#endif /* __ASM_LUAN_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/oak.c b/arch/ppc/platforms/4xx/oak.c new file mode 100644 index 00000000000..fa25ee1fa73 --- /dev/null +++ b/arch/ppc/platforms/4xx/oak.c @@ -0,0 +1,255 @@ +/* + * + * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu> + * + * Module name: oak.c + * + * Description: + * Architecture- / platform-specific boot-time initialization code for + * the IBM PowerPC 403GCX "Oak" evaluation board. Adapted from original + * code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek + * <dan@net4x.com>. + * + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/smp.h> +#include <linux/threads.h> +#include <linux/param.h> +#include <linux/string.h> +#include <linux/initrd.h> +#include <linux/irq.h> +#include <linux/seq_file.h> + +#include <asm/board.h> +#include <asm/machdep.h> +#include <asm/page.h> +#include <asm/bootinfo.h> +#include <asm/ppc4xx_pic.h> +#include <asm/time.h> + +#include "oak.h" + +/* Function Prototypes */ + +extern void abort(void); + +/* Global Variables */ + +unsigned char __res[sizeof(bd_t)]; + + +/* + * void __init oak_init() + * + * Description: + * This routine... + * + * Input(s): + * r3 - Optional pointer to a board information structure. + * r4 - Optional pointer to the physical starting address of the init RAM + * disk. + * r5 - Optional pointer to the physical ending address of the init RAM + * disk. + * r6 - Optional pointer to the physical starting address of any kernel + * command-line parameters. + * r7 - Optional pointer to the physical ending address of any kernel + * command-line parameters. + * + * Output(s): + * N/A + * + * Returns: + * N/A + * + */ +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + parse_bootinfo(find_bootinfo()); + + /* + * If we were passed in a board information, copy it into the + * residual data area. + */ + if (r3) { + memcpy((void *)__res, (void *)(r3 + KERNELBASE), sizeof(bd_t)); + } + +#if defined(CONFIG_BLK_DEV_INITRD) + /* + * If the init RAM disk has been configured in, and there's a valid + * starting address for it, set it up. + */ + if (r4) { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif /* CONFIG_BLK_DEV_INITRD */ + + /* Copy the kernel command line arguments to a safe place. */ + + if (r6) { + *(char *)(r7 + KERNELBASE) = 0; + strcpy(cmd_line, (char *)(r6 + KERNELBASE)); + } + + /* Initialize machine-dependency vectors */ + + ppc_md.setup_arch = oak_setup_arch; + ppc_md.show_percpuinfo = oak_show_percpuinfo; + ppc_md.irq_canonicalize = NULL; + ppc_md.init_IRQ = ppc4xx_pic_init; + ppc_md.get_irq = NULL; /* Set in ppc4xx_pic_init() */ + ppc_md.init = NULL; + + ppc_md.restart = oak_restart; + ppc_md.power_off = oak_power_off; + ppc_md.halt = oak_halt; + + ppc_md.time_init = oak_time_init; + ppc_md.set_rtc_time = oak_set_rtc_time; + ppc_md.get_rtc_time = oak_get_rtc_time; + ppc_md.calibrate_decr = oak_calibrate_decr; +} + +/* + * Document me. + */ +void __init +oak_setup_arch(void) +{ + /* XXX - Implement me */ +} + +/* + * int oak_show_percpuinfo() + * + * Description: + * This routine pretty-prints the platform's internal CPU and bus clock + * frequencies into the buffer for usage in /proc/cpuinfo. + * + * Input(s): + * *buffer - Buffer into which CPU and bus clock frequencies are to be + * printed. + * + * Output(s): + * *buffer - Buffer with the CPU and bus clock frequencies. + * + * Returns: + * The number of bytes copied into 'buffer' if OK, otherwise zero or less + * on error. + */ +int +oak_show_percpuinfo(struct seq_file *m, int i) +{ + bd_t *bp = (bd_t *)__res; + + seq_printf(m, "clock\t\t: %dMHz\n" + "bus clock\t\t: %dMHz\n", + bp->bi_intfreq / 1000000, + bp->bi_busfreq / 1000000); + + return 0; +} + +/* + * Document me. + */ +void +oak_restart(char *cmd) +{ + abort(); +} + +/* + * Document me. + */ +void +oak_power_off(void) +{ + oak_restart(NULL); +} + +/* + * Document me. + */ +void +oak_halt(void) +{ + oak_restart(NULL); +} + +/* + * Document me. + */ +long __init +oak_time_init(void) +{ + /* XXX - Implement me */ + return 0; +} + +/* + * Document me. + */ +int __init +oak_set_rtc_time(unsigned long time) +{ + /* XXX - Implement me */ + + return (0); +} + +/* + * Document me. + */ +unsigned long __init +oak_get_rtc_time(void) +{ + /* XXX - Implement me */ + + return (0); +} + +/* + * void __init oak_calibrate_decr() + * + * Description: + * This routine retrieves the internal processor frequency from the board + * information structure, sets up the kernel timer decrementer based on + * that value, enables the 403 programmable interval timer (PIT) and sets + * it up for auto-reload. + * + * Input(s): + * N/A + * + * Output(s): + * N/A + * + * Returns: + * N/A + * + */ +void __init +oak_calibrate_decr(void) +{ + unsigned int freq; + bd_t *bip = (bd_t *)__res; + + freq = bip->bi_intfreq; + + decrementer_count = freq / HZ; + count_period_num = 1; + count_period_den = freq; + + /* Enable the PIT and set auto-reload of its value */ + + mtspr(SPRN_TCR, TCR_PIE | TCR_ARE); + + /* Clear any pending timer interrupts */ + + mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_PIS | TSR_FIS); +} diff --git a/arch/ppc/platforms/4xx/oak.h b/arch/ppc/platforms/4xx/oak.h new file mode 100644 index 00000000000..1b86a4c66b0 --- /dev/null +++ b/arch/ppc/platforms/4xx/oak.h @@ -0,0 +1,96 @@ +/* + * + * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu> + * + * Module name: oak.h + * + * Description: + * Macros, definitions, and data structures specific to the IBM PowerPC + * 403G{A,B,C,CX} "Oak" evaluation board. Anything specific to the pro- + * cessor itself is defined elsewhere. + * + */ + +#ifdef __KERNEL__ +#ifndef __ASM_OAK_H__ +#define __ASM_OAK_H__ + +/* We have an IBM 403G{A,B,C,CX} core */ +#include <asm/ibm403.h> + +#define _IO_BASE 0 +#define _ISA_MEM_BASE 0 +#define PCI_DRAM_OFFSET 0 + +/* Memory map for the "Oak" evaluation board */ + +#define PPC403SPU_IO_BASE 0x40000000 /* 403 On-chip serial port */ +#define PPC403SPU_IO_SIZE 0x00000008 +#define OAKSERIAL_IO_BASE 0x7E000000 /* NS16550DV serial port */ +#define OAKSERIAL_IO_SIZE 0x00000008 +#define OAKNET_IO_BASE 0xF4000000 /* NS83902AV Ethernet */ +#define OAKNET_IO_SIZE 0x00000040 +#define OAKPROM_IO_BASE 0xFFFE0000 /* AMD 29F010 Flash ROM */ +#define OAKPROM_IO_SIZE 0x00020000 + + +/* Interrupt assignments fixed by the hardware implementation */ + +/* This is annoying kbuild-2.4 problem. -- Tom */ + +#define PPC403SPU_RX_INT 4 /* AIC_INT4 */ +#define PPC403SPU_TX_INT 5 /* AIC_INT5 */ +#define OAKNET_INT 27 /* AIC_INT27 */ +#define OAKSERIAL_INT 28 /* AIC_INT28 */ + +#ifndef __ASSEMBLY__ +/* + * Data structure defining board information maintained by the boot + * ROM on IBM's "Oak" evaluation board. An effort has been made to + * keep the field names consistent with the 8xx 'bd_t' board info + * structures. + */ + +typedef struct board_info { + unsigned char bi_s_version[4]; /* Version of this structure */ + unsigned char bi_r_version[30]; /* Version of the IBM ROM */ + unsigned int bi_memsize; /* DRAM installed, in bytes */ + unsigned char bi_enetaddr[6]; /* Ethernet MAC address */ + unsigned int bi_intfreq; /* Processor speed, in Hz */ + unsigned int bi_busfreq; /* Bus speed, in Hz */ +} bd_t; + +#ifdef __cplusplus +extern "C" { +#endif + +extern void oak_init(unsigned long r3, + unsigned long ird_start, + unsigned long ird_end, + unsigned long cline_start, + unsigned long cline_end); +extern void oak_setup_arch(void); +extern int oak_setup_residual(char *buffer); +extern void oak_init_IRQ(void); +extern int oak_get_irq(struct pt_regs *regs); +extern void oak_restart(char *cmd); +extern void oak_power_off(void); +extern void oak_halt(void); +extern void oak_time_init(void); +extern int oak_set_rtc_time(unsigned long now); +extern unsigned long oak_get_rtc_time(void); +extern void oak_calibrate_decr(void); + +#ifdef __cplusplus +} +#endif + +/* Some 4xx parts use a different timebase frequency from the internal clock. +*/ +#define bi_tbfreq bi_intfreq + +#define PPC4xx_MACHINE_NAME "IBM Oak" + +#endif /* !__ASSEMBLY__ */ +#endif /* __ASM_OAK_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/oak_setup.h b/arch/ppc/platforms/4xx/oak_setup.h new file mode 100644 index 00000000000..8648bd084df --- /dev/null +++ b/arch/ppc/platforms/4xx/oak_setup.h @@ -0,0 +1,50 @@ +/* + * + * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu> + * + * Module name: oak_setup.h + * + * Description: + * Architecture- / platform-specific boot-time initialization code for + * the IBM PowerPC 403GCX "Oak" evaluation board. Adapted from original + * code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek + * <dan@netx4.com>. + * + */ + +#ifndef __OAK_SETUP_H__ +#define __OAK_SETUP_H__ + +#include <asm/ptrace.h> +#include <asm/board.h> + + +#ifdef __cplusplus +extern "C" { +#endif + +extern unsigned char __res[sizeof(bd_t)]; + +extern void oak_init(unsigned long r3, + unsigned long ird_start, + unsigned long ird_end, + unsigned long cline_start, + unsigned long cline_end); +extern void oak_setup_arch(void); +extern int oak_setup_residual(char *buffer); +extern void oak_init_IRQ(void); +extern int oak_get_irq(struct pt_regs *regs); +extern void oak_restart(char *cmd); +extern void oak_power_off(void); +extern void oak_halt(void); +extern void oak_time_init(void); +extern int oak_set_rtc_time(unsigned long now); +extern unsigned long oak_get_rtc_time(void); +extern void oak_calibrate_decr(void); + + +#ifdef __cplusplus +} +#endif + +#endif /* __OAK_SETUP_H__ */ diff --git a/arch/ppc/platforms/4xx/ocotea.c b/arch/ppc/platforms/4xx/ocotea.c new file mode 100644 index 00000000000..28de707434f --- /dev/null +++ b/arch/ppc/platforms/4xx/ocotea.c @@ -0,0 +1,367 @@ +/* + * arch/ppc/platforms/4xx/ocotea.c + * + * Ocotea board specific routines + * + * Matt Porter <mporter@kernel.crashing.org> + * + * Copyright 2003-2005 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/types.h> +#include <linux/major.h> +#include <linux/blkdev.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/ide.h> +#include <linux/initrd.h> +#include <linux/irq.h> +#include <linux/seq_file.h> +#include <linux/root_dev.h> +#include <linux/tty.h> +#include <linux/serial.h> +#include <linux/serial_core.h> + +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/machdep.h> +#include <asm/ocp.h> +#include <asm/pci-bridge.h> +#include <asm/time.h> +#include <asm/todc.h> +#include <asm/bootinfo.h> +#include <asm/ppc4xx_pic.h> +#include <asm/ppcboot.h> + +#include <syslib/gen550.h> +#include <syslib/ibm440gx_common.h> + +/* + * This is a horrible kludge, we eventually need to abstract this + * generic PHY stuff, so the standard phy mode defines can be + * easily used from arch code. + */ +#include "../../../../drivers/net/ibm_emac/ibm_emac_phy.h" + +bd_t __res; + +static struct ibm44x_clocks clocks __initdata; + +static void __init +ocotea_calibrate_decr(void) +{ + unsigned int freq; + + if (mfspr(SPRN_CCR1) & CCR1_TCS) + freq = OCOTEA_TMR_CLK; + else + freq = clocks.cpu; + + ibm44x_calibrate_decr(freq); +} + +static int +ocotea_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "vendor\t\t: IBM\n"); + seq_printf(m, "machine\t\t: PPC440GX EVB (Ocotea)\n"); + ibm440gx_show_cpuinfo(m); + return 0; +} + +static inline int +ocotea_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + { 23, 23, 23, 23 }, /* IDSEL 1 - PCI Slot 0 */ + { 24, 24, 24, 24 }, /* IDSEL 2 - PCI Slot 1 */ + { 25, 25, 25, 25 }, /* IDSEL 3 - PCI Slot 2 */ + { 26, 26, 26, 26 }, /* IDSEL 4 - PCI Slot 3 */ + }; + + const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +} + +static void __init ocotea_set_emacdata(void) +{ + struct ocp_def *def; + struct ocp_func_emac_data *emacdata; + int i; + + /* + * Note: Current rev. board only operates in Group 4a + * mode, so we always set EMAC0-1 for SMII and EMAC2-3 + * for RGMII (though these could run in RTBI just the same). + * + * The FPGA reg 3 information isn't even suitable for + * determining the phy_mode, so if the board becomes + * usable in !4a, it will be necessary to parse an environment + * variable from the firmware or similar to properly configure + * the phy_map/phy_mode. + */ + /* Set phy_map, phy_mode, and mac_addr for each EMAC */ + for (i=0; i<4; i++) { + def = ocp_get_one_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, i); + emacdata = def->additions; + if (i < 2) { + emacdata->phy_map = 0x00000001; /* Skip 0x00 */ + emacdata->phy_mode = PHY_MODE_SMII; + } + else { + emacdata->phy_map = 0x0000ffff; /* Skip 0x00-0x0f */ + emacdata->phy_mode = PHY_MODE_RGMII; + } + if (i == 0) + memcpy(emacdata->mac_addr, __res.bi_enetaddr, 6); + else if (i == 1) + memcpy(emacdata->mac_addr, __res.bi_enet1addr, 6); + else if (i == 2) + memcpy(emacdata->mac_addr, __res.bi_enet2addr, 6); + else if (i == 3) + memcpy(emacdata->mac_addr, __res.bi_enet3addr, 6); + } +} + +#define PCIX_READW(offset) \ + (readw(pcix_reg_base+offset)) + +#define PCIX_WRITEW(value, offset) \ + (writew(value, pcix_reg_base+offset)) + +#define PCIX_WRITEL(value, offset) \ + (writel(value, pcix_reg_base+offset)) + +/* + * FIXME: This is only here to "make it work". This will move + * to a ibm_pcix.c which will contain a generic IBM PCIX bridge + * configuration library. -Matt + */ +static void __init +ocotea_setup_pcix(void) +{ + void *pcix_reg_base; + + pcix_reg_base = ioremap64(PCIX0_REG_BASE, PCIX_REG_SIZE); + + /* Enable PCIX0 I/O, Mem, and Busmaster cycles */ + PCIX_WRITEW(PCIX_READW(PCIX0_COMMAND) | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, PCIX0_COMMAND); + + /* Disable all windows */ + PCIX_WRITEL(0, PCIX0_POM0SA); + PCIX_WRITEL(0, PCIX0_POM1SA); + PCIX_WRITEL(0, PCIX0_POM2SA); + PCIX_WRITEL(0, PCIX0_PIM0SA); + PCIX_WRITEL(0, PCIX0_PIM0SAH); + PCIX_WRITEL(0, PCIX0_PIM1SA); + PCIX_WRITEL(0, PCIX0_PIM2SA); + PCIX_WRITEL(0, PCIX0_PIM2SAH); + + /* Setup 2GB PLB->PCI outbound mem window (3_8000_0000->0_8000_0000) */ + PCIX_WRITEL(0x00000003, PCIX0_POM0LAH); + PCIX_WRITEL(0x80000000, PCIX0_POM0LAL); + PCIX_WRITEL(0x00000000, PCIX0_POM0PCIAH); + PCIX_WRITEL(0x80000000, PCIX0_POM0PCIAL); + PCIX_WRITEL(0x80000001, PCIX0_POM0SA); + + /* Setup 2GB PCI->PLB inbound memory window at 0, enable MSIs */ + PCIX_WRITEL(0x00000000, PCIX0_PIM0LAH); + PCIX_WRITEL(0x00000000, PCIX0_PIM0LAL); + PCIX_WRITEL(0xe0000007, PCIX0_PIM0SA); + + eieio(); +} + +static void __init +ocotea_setup_hose(void) +{ + struct pci_controller *hose; + + /* Configure windows on the PCI-X host bridge */ + ocotea_setup_pcix(); + + hose = pcibios_alloc_controller(); + + if (!hose) + return; + + hose->first_busno = 0; + hose->last_busno = 0xff; + + hose->pci_mem_offset = OCOTEA_PCI_MEM_OFFSET; + + pci_init_resource(&hose->io_resource, + OCOTEA_PCI_LOWER_IO, + OCOTEA_PCI_UPPER_IO, + IORESOURCE_IO, + "PCI host bridge"); + + pci_init_resource(&hose->mem_resources[0], + OCOTEA_PCI_LOWER_MEM, + OCOTEA_PCI_UPPER_MEM, + IORESOURCE_MEM, + "PCI host bridge"); + + hose->io_space.start = OCOTEA_PCI_LOWER_IO; + hose->io_space.end = OCOTEA_PCI_UPPER_IO; + hose->mem_space.start = OCOTEA_PCI_LOWER_MEM; + hose->mem_space.end = OCOTEA_PCI_UPPER_MEM; + isa_io_base = + (unsigned long)ioremap64(OCOTEA_PCI_IO_BASE, OCOTEA_PCI_IO_SIZE); + hose->io_base_virt = (void *)isa_io_base; + + setup_indirect_pci(hose, + OCOTEA_PCI_CFGA_PLB32, + OCOTEA_PCI_CFGD_PLB32); + hose->set_cfg_type = 1; + + hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); + + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = ocotea_map_irq; +} + + +TODC_ALLOC(); + +static void __init +ocotea_early_serial_map(void) +{ + struct uart_port port; + + /* Setup ioremapped serial port access */ + memset(&port, 0, sizeof(port)); + port.membase = ioremap64(PPC440GX_UART0_ADDR, 8); + port.irq = UART0_INT; + port.uartclk = clocks.uart0; + port.regshift = 0; + port.iotype = SERIAL_IO_MEM; + port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST; + port.line = 0; + + if (early_serial_setup(&port) != 0) { + printk("Early serial init of port 0 failed\n"); + } + +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) + /* Configure debug serial access */ + gen550_init(0, &port); +#endif + + port.membase = ioremap64(PPC440GX_UART1_ADDR, 8); + port.irq = UART1_INT; + port.uartclk = clocks.uart1; + port.line = 1; + + if (early_serial_setup(&port) != 0) { + printk("Early serial init of port 1 failed\n"); + } + +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) + /* Configure debug serial access */ + gen550_init(1, &port); +#endif +} + +static void __init +ocotea_setup_arch(void) +{ + ocotea_set_emacdata(); + + ibm440gx_tah_enable(); + + /* Setup TODC access */ + TODC_INIT(TODC_TYPE_DS1743, + 0, + 0, + ioremap64(OCOTEA_RTC_ADDR, OCOTEA_RTC_SIZE), + 8); + + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000/HZ; + + /* Setup PCI host bridge */ + ocotea_setup_hose(); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_HDA1; +#endif + + ocotea_early_serial_map(); + + /* Identify the system */ + printk("IBM Ocotea port (MontaVista Software, Inc. <source@mvista.com>)\n"); +} + +static void __init ocotea_init(void) +{ + ibm440gx_l2c_setup(&clocks); +} + +void __init platform_init(unsigned long r3, unsigned long r4, + unsigned long r5, unsigned long r6, unsigned long r7) +{ + parse_bootinfo(find_bootinfo()); + + /* + * If we were passed in a board information, copy it into the + * residual data area. + */ + if (r3) + __res = *(bd_t *)(r3 + KERNELBASE); + + /* + * Determine various clocks. + * To be completely correct we should get SysClk + * from FPGA, because it can be changed by on-board switches + * --ebs + */ + ibm440gx_get_clocks(&clocks, 33333333, 6 * 1843200); + ocp_sys_info.opb_bus_freq = clocks.opb; + + ibm44x_platform_init(); + + ppc_md.setup_arch = ocotea_setup_arch; + ppc_md.show_cpuinfo = ocotea_show_cpuinfo; + ppc_md.get_irq = NULL; /* Set in ppc4xx_pic_init() */ + + ppc_md.calibrate_decr = ocotea_calibrate_decr; + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; +#ifdef CONFIG_KGDB + ppc_md.early_serial_map = ocotea_early_serial_map; +#endif + ppc_md.init = ocotea_init; +} diff --git a/arch/ppc/platforms/4xx/ocotea.h b/arch/ppc/platforms/4xx/ocotea.h new file mode 100644 index 00000000000..202dc825119 --- /dev/null +++ b/arch/ppc/platforms/4xx/ocotea.h @@ -0,0 +1,88 @@ +/* + * arch/ppc/platforms/ocotea.h + * + * Ocotea board definitions + * + * Matt Porter <mporter@kernel.crashing.org> + * + * Copyright 2003-2005 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifdef __KERNEL__ +#ifndef __ASM_OCOTEA_H__ +#define __ASM_OCOTEA_H__ + +#include <linux/config.h> +#include <platforms/4xx/ibm440gx.h> + +/* F/W TLB mapping used in bootloader glue to reset EMAC */ +#define PPC44x_EMAC0_MR0 0xe0000800 + +/* Location of MAC addresses in PIBS image */ +#define PIBS_FLASH_BASE 0xfff00000 +#define PIBS_MAC_BASE (PIBS_FLASH_BASE+0xb0500) +#define PIBS_MAC_SIZE 0x200 +#define PIBS_MAC_OFFSET 0x100 + +/* External timer clock frequency */ +#define OCOTEA_TMR_CLK 25000000 + +/* RTC/NVRAM location */ +#define OCOTEA_RTC_ADDR 0x0000000148000000ULL +#define OCOTEA_RTC_SIZE 0x2000 + +/* Flash */ +#define OCOTEA_FPGA_REG_0 0x0000000148300000ULL +#define OCOTEA_BOOT_LARGE_FLASH(x) (x & 0x40) +#define OCOTEA_SMALL_FLASH_LOW 0x00000001ff900000ULL +#define OCOTEA_SMALL_FLASH_HIGH 0x00000001fff00000ULL +#define OCOTEA_SMALL_FLASH_SIZE 0x100000 +#define OCOTEA_LARGE_FLASH_LOW 0x00000001ff800000ULL +#define OCOTEA_LARGE_FLASH_HIGH 0x00000001ffc00000ULL +#define OCOTEA_LARGE_FLASH_SIZE 0x400000 + +/* FPGA_REG_3 (Ethernet Groups) */ +#define OCOTEA_FPGA_REG_3 0x0000000148300003ULL + +/* + * Serial port defines + */ +#define RS_TABLE_SIZE 2 + +/* OpenBIOS defined UART mappings, used before early_serial_setup */ +#define UART0_IO_BASE 0xE0000200 +#define UART1_IO_BASE 0xE0000300 + +#define BASE_BAUD 11059200/16 +#define STD_UART_OP(num) \ + { 0, BASE_BAUD, 0, UART##num##_INT, \ + (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \ + iomem_base: UART##num##_IO_BASE, \ + io_type: SERIAL_IO_MEM}, + +#define SERIAL_PORT_DFNS \ + STD_UART_OP(0) \ + STD_UART_OP(1) + +/* PCI support */ +#define OCOTEA_PCI_LOWER_IO 0x00000000 +#define OCOTEA_PCI_UPPER_IO 0x0000ffff +#define OCOTEA_PCI_LOWER_MEM 0x80000000 +#define OCOTEA_PCI_UPPER_MEM 0xffffefff + +#define OCOTEA_PCI_CFGREGS_BASE 0x000000020ec00000ULL +#define OCOTEA_PCI_CFGA_PLB32 0x0ec00000 +#define OCOTEA_PCI_CFGD_PLB32 0x0ec00004 + +#define OCOTEA_PCI_IO_BASE 0x0000000208000000ULL +#define OCOTEA_PCI_IO_SIZE 0x00010000 +#define OCOTEA_PCI_MEM_OFFSET 0x00000000 + +#endif /* __ASM_OCOTEA_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/redwood5.c b/arch/ppc/platforms/4xx/redwood5.c new file mode 100644 index 00000000000..2f5e410afbc --- /dev/null +++ b/arch/ppc/platforms/4xx/redwood5.c @@ -0,0 +1,110 @@ +/* + * arch/ppc/platforms/4xx/redwood5.c + * + * Support for the IBM redwood5 eval board file + * + * Author: Armin Kuster <akuster@mvista.com> + * + * 2000-2001 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/pagemap.h> +#include <linux/device.h> +#include <linux/ioport.h> +#include <asm/io.h> +#include <asm/machdep.h> + +static struct resource smc91x_resources[] = { + [0] = { + .start = SMC91111_BASE_ADDR, + .end = SMC91111_BASE_ADDR + SMC91111_REG_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = SMC91111_IRQ, + .end = SMC91111_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +static struct platform_device *redwood5_devs[] __initdata = { + &smc91x_device, +}; + +static int __init +redwood5_platform_add_devices(void) +{ + return platform_add_devices(redwood5_devs, ARRAY_SIZE(redwood5_devs)); +} + +void __init +redwood5_setup_arch(void) +{ + ppc4xx_setup_arch(); + +#ifdef CONFIG_DEBUG_BRINGUP + printk("\n"); + printk("machine\t: %s\n", PPC4xx_MACHINE_NAME); + printk("\n"); + printk("bi_s_version\t %s\n", bip->bi_s_version); + printk("bi_r_version\t %s\n", bip->bi_r_version); + printk("bi_memsize\t 0x%8.8x\t %dMBytes\n", bip->bi_memsize,bip->bi_memsize/(1024*1000)); + printk("bi_enetaddr %d\t %2.2x%2.2x%2.2x-%2.2x%2.2x%2.2x\n", 0, + bip->bi_enetaddr[0], bip->bi_enetaddr[1], + bip->bi_enetaddr[2], bip->bi_enetaddr[3], + bip->bi_enetaddr[4], bip->bi_enetaddr[5]); + + printk("bi_intfreq\t 0x%8.8x\t clock:\t %dMhz\n", + bip->bi_intfreq, bip->bi_intfreq/ 1000000); + + printk("bi_busfreq\t 0x%8.8x\t plb bus clock:\t %dMHz\n", + bip->bi_busfreq, bip->bi_busfreq / 1000000 ); + printk("bi_tbfreq\t 0x%8.8x\t TB freq:\t %dMHz\n", + bip->bi_tbfreq, bip->bi_tbfreq/1000000); + + printk("\n"); +#endif + device_initcall(redwood5_platform_add_devices); +} + +void __init +redwood5_map_io(void) +{ + int i; + + ppc4xx_map_io(); + for (i = 0; i < 16; i++) { + unsigned long v, p; + + /* 0x400x0000 -> 0xe00x0000 */ + p = 0x40000000 | (i << 16); + v = STB04xxx_IO_BASE | (i << 16); + + io_block_mapping(v, p, PAGE_SIZE, + _PAGE_NO_CACHE | pgprot_val(PAGE_KERNEL) | _PAGE_GUARDED); + } + + +} + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + ppc4xx_init(r3, r4, r5, r6, r7); + + ppc_md.setup_arch = redwood5_setup_arch; + ppc_md.setup_io_mappings = redwood5_map_io; +} diff --git a/arch/ppc/platforms/4xx/redwood5.h b/arch/ppc/platforms/4xx/redwood5.h new file mode 100644 index 00000000000..264e34fb3fb --- /dev/null +++ b/arch/ppc/platforms/4xx/redwood5.h @@ -0,0 +1,54 @@ +/* + * arch/ppc/platforms/4xx/redwood5.h + * + * Macros, definitions, and data structures specific to the IBM PowerPC + * STB03xxx "Redwood" evaluation board. + * + * Author: Armin Kuster <akuster@mvista.com> + * + * 2001 (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. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_REDWOOD5_H__ +#define __ASM_REDWOOD5_H__ + +/* Redwood5 has an STB04xxx core */ +#include <platforms/4xx/ibmstb4.h> + +#ifndef __ASSEMBLY__ +typedef struct board_info { + unsigned char bi_s_version[4]; /* Version of this structure */ + unsigned char bi_r_version[30]; /* Version of the IBM ROM */ + unsigned int bi_memsize; /* DRAM installed, in bytes */ + unsigned int bi_dummy; /* field shouldn't exist */ + unsigned char bi_enetaddr[6]; /* Ethernet MAC address */ + unsigned int bi_intfreq; /* Processor speed, in Hz */ + unsigned int bi_busfreq; /* Bus speed, in Hz */ + unsigned int bi_tbfreq; /* Software timebase freq */ +} bd_t; +#endif /* !__ASSEMBLY__ */ + + +#define SMC91111_BASE_ADDR 0xf2000300 +#define SMC91111_REG_SIZE 16 +#define SMC91111_IRQ 28 + +#ifdef MAX_HWIFS +#undef MAX_HWIFS +#endif +#define MAX_HWIFS 1 + +#define _IO_BASE 0 +#define _ISA_MEM_BASE 0 +#define PCI_DRAM_OFFSET 0 + +#define BASE_BAUD (378000000 / 18 / 16) + +#define PPC4xx_MACHINE_NAME "IBM Redwood5" + +#endif /* __ASM_REDWOOD5_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/redwood6.c b/arch/ppc/platforms/4xx/redwood6.c new file mode 100644 index 00000000000..8b1012994df --- /dev/null +++ b/arch/ppc/platforms/4xx/redwood6.c @@ -0,0 +1,159 @@ +/* + * arch/ppc/platforms/4xx/redwood6.c + * + * Author: Armin Kuster <akuster@mvista.com> + * + * 2002 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/pagemap.h> +#include <linux/device.h> +#include <linux/ioport.h> +#include <asm/io.h> +#include <asm/ppc4xx_pic.h> +#include <linux/delay.h> +#include <asm/machdep.h> + +/* + * Define external IRQ senses and polarities. + */ +unsigned char ppc4xx_uic_ext_irq_cfg[] __initdata = { + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 7 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 8 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 9 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 3 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 4 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 5 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 6 */ +}; + +static struct resource smc91x_resources[] = { + [0] = { + .start = SMC91111_BASE_ADDR, + .end = SMC91111_BASE_ADDR + SMC91111_REG_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = SMC91111_IRQ, + .end = SMC91111_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +static struct platform_device *redwood6_devs[] __initdata = { + &smc91x_device, +}; + +static int __init +redwood6_platform_add_devices(void) +{ + return platform_add_devices(redwood6_devs, ARRAY_SIZE(redwood6_devs)); +} + + +void __init +redwood6_setup_arch(void) +{ +#ifdef CONFIG_IDE + void *xilinx, *xilinx_1, *xilinx_2; + unsigned short us_reg5; +#endif + + ppc4xx_setup_arch(); + +#ifdef CONFIG_IDE + xilinx = (unsigned long) ioremap(IDE_XLINUX_MUX_BASE, 0x10); + /* init xilinx control registers - enable ide mux, clear reset bit */ + if (!xilinx) { + printk(KERN_CRIT + "redwood6_setup_arch() xilinxi ioremap failed\n"); + return; + } + xilinx_1 = xilinx + 0xa; + xilinx_2 = xilinx + 0xe; + + us_reg5 = readb(xilinx_1); + writeb(0x01d1, xilinx_1); + writeb(0x0008, xilinx_2); + + udelay(10 * 1000); + + writeb(0x01d1, xilinx_1); + writeb(0x0008, xilinx_2); +#endif + +#ifdef DEBUG_BRINGUP + bd_t *bip = (bd_t *) __res; + printk("\n"); + printk("machine\t: %s\n", PPC4xx_MACHINE_NAME); + printk("\n"); + printk("bi_s_version\t %s\n", bip->bi_s_version); + printk("bi_r_version\t %s\n", bip->bi_r_version); + printk("bi_memsize\t 0x%8.8x\t %dMBytes\n", bip->bi_memsize, + bip->bi_memsize / (1024 * 1000)); + printk("bi_enetaddr %d\t %2.2x%2.2x%2.2x-%2.2x%2.2x%2.2x\n", 0, + bip->bi_enetaddr[0], bip->bi_enetaddr[1], bip->bi_enetaddr[2], + bip->bi_enetaddr[3], bip->bi_enetaddr[4], bip->bi_enetaddr[5]); + + printk("bi_intfreq\t 0x%8.8x\t clock:\t %dMhz\n", + bip->bi_intfreq, bip->bi_intfreq / 1000000); + + printk("bi_busfreq\t 0x%8.8x\t plb bus clock:\t %dMHz\n", + bip->bi_busfreq, bip->bi_busfreq / 1000000); + printk("bi_tbfreq\t 0x%8.8x\t TB freq:\t %dMHz\n", + bip->bi_tbfreq, bip->bi_tbfreq / 1000000); + + printk("\n"); +#endif + + /* Identify the system */ + printk(KERN_INFO "IBM Redwood6 (STBx25XX) Platform\n"); + printk(KERN_INFO + "Port by MontaVista Software, Inc. (source@mvista.com)\n"); + + device_initcall(redwood6_platform_add_devices); +} + +void __init +redwood6_map_io(void) +{ + int i; + + ppc4xx_map_io(); + for (i = 0; i < 16; i++) { + unsigned long v, p; + + /* 0x400x0000 -> 0xe00x0000 */ + p = 0x40000000 | (i << 16); + v = STBx25xx_IO_BASE | (i << 16); + + io_block_mapping(v, p, PAGE_SIZE, + _PAGE_NO_CACHE | pgprot_val(PAGE_KERNEL) | + _PAGE_GUARDED); + } +} + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + ppc4xx_init(r3, r4, r5, r6, r7); + + ppc_md.setup_arch = redwood6_setup_arch; + ppc_md.setup_io_mappings = redwood6_map_io; +} diff --git a/arch/ppc/platforms/4xx/redwood6.h b/arch/ppc/platforms/4xx/redwood6.h new file mode 100644 index 00000000000..1814b9f5fc3 --- /dev/null +++ b/arch/ppc/platforms/4xx/redwood6.h @@ -0,0 +1,55 @@ +/* + * arch/ppc/platforms/4xx/redwood6.h + * + * Macros, definitions, and data structures specific to the IBM PowerPC + * STBx25xx "Redwood6" evaluation board. + * + * Author: Armin Kuster <akuster@mvista.com> + * + * 2002 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_REDWOOD5_H__ +#define __ASM_REDWOOD5_H__ + +/* Redwood6 has an STBx25xx core */ +#include <platforms/4xx/ibmstbx25.h> + +#ifndef __ASSEMBLY__ +typedef struct board_info { + unsigned char bi_s_version[4]; /* Version of this structure */ + unsigned char bi_r_version[30]; /* Version of the IBM ROM */ + unsigned int bi_memsize; /* DRAM installed, in bytes */ + unsigned int bi_dummy; /* field shouldn't exist */ + unsigned char bi_enetaddr[6]; /* Ethernet MAC address */ + unsigned int bi_intfreq; /* Processor speed, in Hz */ + unsigned int bi_busfreq; /* Bus speed, in Hz */ + unsigned int bi_tbfreq; /* Software timebase freq */ +} bd_t; +#endif /* !__ASSEMBLY__ */ + +#define SMC91111_BASE_ADDR 0xf2030300 +#define SMC91111_REG_SIZE 16 +#define SMC91111_IRQ 27 +#define IDE_XLINUX_MUX_BASE 0xf2040000 +#define IDE_DMA_ADDR 0xfce00000 + +#ifdef MAX_HWIFS +#undef MAX_HWIFS +#endif +#define MAX_HWIFS 1 + +#define _IO_BASE 0 +#define _ISA_MEM_BASE 0 +#define PCI_DRAM_OFFSET 0 + +#define BASE_BAUD (378000000 / 18 / 16) + +#define PPC4xx_MACHINE_NAME "IBM Redwood6" + +#endif /* __ASM_REDWOOD5_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/sycamore.c b/arch/ppc/platforms/4xx/sycamore.c new file mode 100644 index 00000000000..d8019eec470 --- /dev/null +++ b/arch/ppc/platforms/4xx/sycamore.c @@ -0,0 +1,278 @@ +/* + * arch/ppc/platforms/4xx/sycamore.c + * + * Architecture- / platform-specific boot-time initialization code for + * IBM PowerPC 4xx based boards. + * + * Author: Armin Kuster <akuster@mvista.com> + * + * 2000-2002 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/smp.h> +#include <linux/threads.h> +#include <linux/param.h> +#include <linux/string.h> +#include <linux/pci.h> +#include <linux/rtc.h> + +#include <asm/ocp.h> +#include <asm/ppc4xx_pic.h> +#include <asm/system.h> +#include <asm/pci-bridge.h> +#include <asm/machdep.h> +#include <asm/page.h> +#include <asm/time.h> +#include <asm/io.h> +#include <asm/ibm_ocp_pci.h> +#include <asm/todc.h> + +#undef DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +void *kb_cs; +void *kb_data; +void *sycamore_rtc_base; + +/* + * Define external IRQ senses and polarities. + */ +unsigned char ppc4xx_uic_ext_irq_cfg[] __initdata = { + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 7 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 8 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 9 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 10 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 11 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 12 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 3 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 4 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 5 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 6 */ +}; + + +/* Some IRQs unique to Sycamore. + * Used by the generic 405 PCI setup functions in ppc4xx_pci.c + */ +int __init +ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {28, 28, 28, 28}, /* IDSEL 1 - PCI slot 1 */ + {29, 29, 29, 29}, /* IDSEL 2 - PCI slot 2 */ + {30, 30, 30, 30}, /* IDSEL 3 - PCI slot 3 */ + {31, 31, 31, 31}, /* IDSEL 4 - PCI slot 4 */ + }; + + const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +}; + +void __init +sycamore_setup_arch(void) +{ +#define SYCAMORE_PS2_BASE 0xF0100000 +#define SYCAMORE_FPGA_BASE 0xF0300000 + + void *fpga_brdc; + unsigned char fpga_brdc_data; + void *fpga_enable; + void *fpga_polarity; + void *fpga_status; + void *fpga_trigger; + + ppc4xx_setup_arch(); + + ibm_ocp_set_emac(0, 1); + + kb_data = ioremap(SYCAMORE_PS2_BASE, 8); + if (!kb_data) { + printk(KERN_CRIT + "sycamore_setup_arch() kb_data ioremap failed\n"); + return; + } + + kb_cs = kb_data + 1; + + fpga_status = ioremap(SYCAMORE_FPGA_BASE, 8); + if (!fpga_status) { + printk(KERN_CRIT + "sycamore_setup_arch() fpga_status ioremap failed\n"); + return; + } + + fpga_enable = fpga_status + 1; + fpga_polarity = fpga_status + 2; + fpga_trigger = fpga_status + 3; + fpga_brdc = fpga_status + 4; + + /* split the keyboard and mouse interrupts */ + fpga_brdc_data = readb(fpga_brdc); + fpga_brdc_data |= 0x80; + writeb(fpga_brdc_data, fpga_brdc); + + writeb(0x3, fpga_enable); + + writeb(0x3, fpga_polarity); + + writeb(0x3, fpga_trigger); + + /* RTC step for the sycamore */ + sycamore_rtc_base = (void *) SYCAMORE_RTC_VADDR; + TODC_INIT(TODC_TYPE_DS1743, sycamore_rtc_base, sycamore_rtc_base, + sycamore_rtc_base, 8); + + /* Identify the system */ + printk(KERN_INFO "IBM Sycamore (IBM405GPr) Platform\n"); + printk(KERN_INFO + "Port by MontaVista Software, Inc. (source@mvista.com)\n"); +} + +void __init +bios_fixup(struct pci_controller *hose, struct pcil0_regs *pcip) +{ +#ifdef CONFIG_PCI + unsigned int bar_response, bar; + /* + * Expected PCI mapping: + * + * PLB addr PCI memory addr + * --------------------- --------------------- + * 0000'0000 - 7fff'ffff <--- 0000'0000 - 7fff'ffff + * 8000'0000 - Bfff'ffff ---> 8000'0000 - Bfff'ffff + * + * PLB addr PCI io addr + * --------------------- --------------------- + * e800'0000 - e800'ffff ---> 0000'0000 - 0001'0000 + * + * The following code is simplified by assuming that the bootrom + * has been well behaved in following this mapping. + */ + +#ifdef DEBUG + int i; + + printk("ioremap PCLIO_BASE = 0x%x\n", pcip); + printk("PCI bridge regs before fixup \n"); + for (i = 0; i <= 3; i++) { + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma))); + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la))); + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila))); + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha))); + } + printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms))); + printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la))); + printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms))); + printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la))); + +#endif + + /* added for IBM boot rom version 1.15 bios bar changes -AK */ + + /* Disable region first */ + out_le32((void *) &(pcip->pmm[0].ma), 0x00000000); + /* PLB starting addr, PCI: 0x80000000 */ + out_le32((void *) &(pcip->pmm[0].la), 0x80000000); + /* PCI start addr, 0x80000000 */ + out_le32((void *) &(pcip->pmm[0].pcila), PPC405_PCI_MEM_BASE); + /* 512MB range of PLB to PCI */ + out_le32((void *) &(pcip->pmm[0].pciha), 0x00000000); + /* Enable no pre-fetch, enable region */ + out_le32((void *) &(pcip->pmm[0].ma), ((0xffffffff - + (PPC405_PCI_UPPER_MEM - + PPC405_PCI_MEM_BASE)) | 0x01)); + + /* Enable inbound region one - 1GB size */ + out_le32((void *) &(pcip->ptm1ms), 0xc0000001); + + /* Disable outbound region one */ + out_le32((void *) &(pcip->pmm[1].ma), 0x00000000); + out_le32((void *) &(pcip->pmm[1].la), 0x00000000); + out_le32((void *) &(pcip->pmm[1].pcila), 0x00000000); + out_le32((void *) &(pcip->pmm[1].pciha), 0x00000000); + out_le32((void *) &(pcip->pmm[1].ma), 0x00000000); + + /* Disable inbound region two */ + out_le32((void *) &(pcip->ptm2ms), 0x00000000); + + /* Disable outbound region two */ + out_le32((void *) &(pcip->pmm[2].ma), 0x00000000); + out_le32((void *) &(pcip->pmm[2].la), 0x00000000); + out_le32((void *) &(pcip->pmm[2].pcila), 0x00000000); + out_le32((void *) &(pcip->pmm[2].pciha), 0x00000000); + out_le32((void *) &(pcip->pmm[2].ma), 0x00000000); + + /* Zero config bars */ + for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) { + early_write_config_dword(hose, hose->first_busno, + PCI_FUNC(hose->first_busno), bar, + 0x00000000); + early_read_config_dword(hose, hose->first_busno, + PCI_FUNC(hose->first_busno), bar, + &bar_response); + DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n", + hose->first_busno, PCI_SLOT(hose->first_busno), + PCI_FUNC(hose->first_busno), bar, bar_response); + } + /* end work arround */ + +#ifdef DEBUG + printk("PCI bridge regs after fixup \n"); + for (i = 0; i <= 3; i++) { + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma))); + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la))); + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila))); + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha))); + } + printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms))); + printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la))); + printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms))); + printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la))); + +#endif +#endif + +} + +void __init +sycamore_map_io(void) +{ + ppc4xx_map_io(); + io_block_mapping(SYCAMORE_RTC_VADDR, + SYCAMORE_RTC_PADDR, SYCAMORE_RTC_SIZE, _PAGE_IO); +} + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + ppc4xx_init(r3, r4, r5, r6, r7); + + ppc_md.setup_arch = sycamore_setup_arch; + ppc_md.setup_io_mappings = sycamore_map_io; + +#ifdef CONFIG_GEN_RTC + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; +#endif +} diff --git a/arch/ppc/platforms/4xx/sycamore.h b/arch/ppc/platforms/4xx/sycamore.h new file mode 100644 index 00000000000..3e7b4e2c8c5 --- /dev/null +++ b/arch/ppc/platforms/4xx/sycamore.h @@ -0,0 +1,67 @@ +/* + * arch/ppc/platforms/4xx/sycamore.h + * + * Macros, definitions, and data structures specific to the IBM PowerPC + * 405GPr "Sycamore" evaluation board. + * + * Author: Armin Kuster <akuster@mvista.com> + * + * 2000 (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. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_SYCAMORE_H__ +#define __ASM_SYCAMORE_H__ + +#include <platforms/4xx/ibm405gpr.h> + +#ifndef __ASSEMBLY__ +/* + * Data structure defining board information maintained by the boot + * ROM on IBM's "Sycamore" evaluation board. An effort has been made to + * keep the field names consistent with the 8xx 'bd_t' board info + * structures. + */ + +typedef struct board_info { + unsigned char bi_s_version[4]; /* Version of this structure */ + unsigned char bi_r_version[30]; /* Version of the IBM ROM */ + unsigned int bi_memsize; /* DRAM installed, in bytes */ + unsigned char bi_enetaddr[6]; /* Local Ethernet MAC address */ + unsigned char bi_pci_enetaddr[6]; /* PCI Ethernet MAC address */ + unsigned int bi_intfreq; /* Processor speed, in Hz */ + unsigned int bi_busfreq; /* PLB Bus speed, in Hz */ + unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */ +} bd_t; + +/* Some 4xx parts use a different timebase frequency from the internal clock. +*/ +#define bi_tbfreq bi_intfreq + + +/* Memory map for the IBM "Sycamore" 405GP evaluation board. + * Generic 4xx plus RTC. + */ + +extern void *sycamore_rtc_base; +#define SYCAMORE_RTC_PADDR ((uint)0xf0000000) +#define SYCAMORE_RTC_VADDR SYCAMORE_RTC_PADDR +#define SYCAMORE_RTC_SIZE ((uint)8*1024) + +#ifdef CONFIG_PPC405GP_INTERNAL_CLOCK +#define BASE_BAUD 201600 +#else +#define BASE_BAUD 691200 +#endif + +#define SYCAMORE_PS2_BASE 0xF0100000 +#define SYCAMORE_FPGA_BASE 0xF0300000 + +#define PPC4xx_MACHINE_NAME "IBM Sycamore" + +#endif /* !__ASSEMBLY__ */ +#endif /* __ASM_SYCAMORE_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/virtex-ii_pro.c b/arch/ppc/platforms/4xx/virtex-ii_pro.c new file mode 100644 index 00000000000..097cc9d5aca --- /dev/null +++ b/arch/ppc/platforms/4xx/virtex-ii_pro.c @@ -0,0 +1,60 @@ +/* + * arch/ppc/platforms/4xx/virtex-ii_pro.c + * + * Author: MontaVista Software, Inc. + * source@mvista.com + * + * 2002-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. + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <asm/ocp.h> +#include "virtex-ii_pro.h" + +/* Have OCP take care of the serial ports. */ +struct ocp_def core_ocp[] = { +#ifdef XPAR_UARTNS550_0_BASEADDR + { .vendor = OCP_VENDOR_XILINX, + .function = OCP_FUNC_16550, + .index = 0, + .paddr = XPAR_UARTNS550_0_BASEADDR, + .irq = XPAR_INTC_0_UARTNS550_0_VEC_ID, + .pm = OCP_CPM_NA + }, +#ifdef XPAR_UARTNS550_1_BASEADDR + { .vendor = OCP_VENDOR_XILINX, + .function = OCP_FUNC_16550, + .index = 1, + .paddr = XPAR_UARTNS550_1_BASEADDR, + .irq = XPAR_INTC_0_UARTNS550_1_VEC_ID, + .pm = OCP_CPM_NA + }, +#ifdef XPAR_UARTNS550_2_BASEADDR + { .vendor = OCP_VENDOR_XILINX, + .function = OCP_FUNC_16550, + .index = 2, + .paddr = XPAR_UARTNS550_2_BASEADDR, + .irq = XPAR_INTC_0_UARTNS550_2_VEC_ID, + .pm = OCP_CPM_NA + }, +#ifdef XPAR_UARTNS550_3_BASEADDR + { .vendor = OCP_VENDOR_XILINX, + .function = OCP_FUNC_16550, + .index = 3, + .paddr = XPAR_UARTNS550_3_BASEADDR, + .irq = XPAR_INTC_0_UARTNS550_3_VEC_ID, + .pm = OCP_CPM_NA + }, +#ifdef XPAR_UARTNS550_4_BASEADDR +#error Edit this file to add more devices. +#endif /* 4 */ +#endif /* 3 */ +#endif /* 2 */ +#endif /* 1 */ +#endif /* 0 */ + { .vendor = OCP_VENDOR_INVALID + } +}; diff --git a/arch/ppc/platforms/4xx/virtex-ii_pro.h b/arch/ppc/platforms/4xx/virtex-ii_pro.h new file mode 100644 index 00000000000..9014c488733 --- /dev/null +++ b/arch/ppc/platforms/4xx/virtex-ii_pro.h @@ -0,0 +1,99 @@ +/* + * arch/ppc/platforms/4xx/virtex-ii_pro.h + * + * Include file that defines the Xilinx Virtex-II Pro processor + * + * Author: MontaVista Software, Inc. + * source@mvista.com + * + * 2002-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. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_VIRTEXIIPRO_H__ +#define __ASM_VIRTEXIIPRO_H__ + +#include <linux/config.h> +#include <asm/xparameters.h> + +/* serial defines */ + +#define RS_TABLE_SIZE 4 /* change this and add more devices below + if you have more then 4 16x50 UARTs */ + +#define BASE_BAUD (XPAR_UARTNS550_0_CLOCK_FREQ_HZ/16) + +/* The serial ports in the Virtex-II Pro have each I/O byte in the + * LSByte of a word. This means that iomem_reg_shift needs to be 2 to + * change the byte offsets into word offsets. In addition the base + * addresses need to have 3 added to them to get to the LSByte. + */ +#define STD_UART_OP(num) \ + { 0, BASE_BAUD, 0, XPAR_INTC_0_UARTNS550_##num##_VEC_ID, \ + ASYNC_BOOT_AUTOCONF, \ + .iomem_base = (u8 *)XPAR_UARTNS550_##num##_BASEADDR + 3, \ + .iomem_reg_shift = 2, \ + .io_type = SERIAL_IO_MEM}, + +#if defined(XPAR_INTC_0_UARTNS550_0_VEC_ID) +#define ML300_UART0 STD_UART_OP(0) +#else +#define ML300_UART0 +#endif + +#if defined(XPAR_INTC_0_UARTNS550_1_VEC_ID) +#define ML300_UART1 STD_UART_OP(1) +#else +#define ML300_UART1 +#endif + +#if defined(XPAR_INTC_0_UARTNS550_2_VEC_ID) +#define ML300_UART2 STD_UART_OP(2) +#else +#define ML300_UART2 +#endif + +#if defined(XPAR_INTC_0_UARTNS550_3_VEC_ID) +#define ML300_UART3 STD_UART_OP(3) +#else +#define ML300_UART3 +#endif + +#if defined(XPAR_INTC_0_UARTNS550_4_VEC_ID) +#error Edit this file to add more devices. +#elif defined(XPAR_INTC_0_UARTNS550_3_VEC_ID) +#define NR_SER_PORTS 4 +#elif defined(XPAR_INTC_0_UARTNS550_2_VEC_ID) +#define NR_SER_PORTS 3 +#elif defined(XPAR_INTC_0_UARTNS550_1_VEC_ID) +#define NR_SER_PORTS 2 +#elif defined(XPAR_INTC_0_UARTNS550_0_VEC_ID) +#define NR_SER_PORTS 1 +#else +#define NR_SER_PORTS 0 +#endif + +#if defined(CONFIG_UART0_TTYS0) +#define SERIAL_PORT_DFNS \ + ML300_UART0 \ + ML300_UART1 \ + ML300_UART2 \ + ML300_UART3 +#endif + +#if defined(CONFIG_UART0_TTYS1) +#define SERIAL_PORT_DFNS \ + ML300_UART1 \ + ML300_UART0 \ + ML300_UART2 \ + ML300_UART3 +#endif + +#define DCRN_CPMFR_BASE 0 + +#include <asm/ibm405.h> + +#endif /* __ASM_VIRTEXIIPRO_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/walnut.c b/arch/ppc/platforms/4xx/walnut.c new file mode 100644 index 00000000000..a33eda4b748 --- /dev/null +++ b/arch/ppc/platforms/4xx/walnut.c @@ -0,0 +1,249 @@ +/* + * arch/ppc/platforms/4xx/walnut.c + * + * Architecture- / platform-specific boot-time initialization code for + * IBM PowerPC 4xx based boards. Adapted from original + * code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek + * <dan@net4x.com>. + * + * Copyright(c) 1999-2000 Grant Erickson <grant@lcse.umn.edu> + * + * 2002 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/smp.h> +#include <linux/threads.h> +#include <linux/param.h> +#include <linux/string.h> +#include <linux/pci.h> +#include <linux/rtc.h> + +#include <asm/system.h> +#include <asm/pci-bridge.h> +#include <asm/machdep.h> +#include <asm/page.h> +#include <asm/time.h> +#include <asm/io.h> +#include <asm/ocp.h> +#include <asm/ibm_ocp_pci.h> +#include <asm/todc.h> + +#undef DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +void *kb_cs; +void *kb_data; +void *walnut_rtc_base; + +/* Some IRQs unique to Walnut. + * Used by the generic 405 PCI setup functions in ppc4xx_pci.c + */ +int __init +ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {28, 28, 28, 28}, /* IDSEL 1 - PCI slot 1 */ + {29, 29, 29, 29}, /* IDSEL 2 - PCI slot 2 */ + {30, 30, 30, 30}, /* IDSEL 3 - PCI slot 3 */ + {31, 31, 31, 31}, /* IDSEL 4 - PCI slot 4 */ + }; + + const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +}; + +void __init +walnut_setup_arch(void) +{ + + void *fpga_brdc; + unsigned char fpga_brdc_data; + void *fpga_enable; + void *fpga_polarity; + void *fpga_status; + void *fpga_trigger; + + ppc4xx_setup_arch(); + + ibm_ocp_set_emac(0, 0); + + kb_data = ioremap(WALNUT_PS2_BASE, 8); + if (!kb_data) { + printk(KERN_CRIT + "walnut_setup_arch() kb_data ioremap failed\n"); + return; + } + + kb_cs = kb_data + 1; + + fpga_status = ioremap(WALNUT_FPGA_BASE, 8); + if (!fpga_status) { + printk(KERN_CRIT + "walnut_setup_arch() fpga_status ioremap failed\n"); + return; + } + + fpga_enable = fpga_status + 1; + fpga_polarity = fpga_status + 2; + fpga_trigger = fpga_status + 3; + fpga_brdc = fpga_status + 4; + + /* split the keyboard and mouse interrupts */ + fpga_brdc_data = readb(fpga_brdc); + fpga_brdc_data |= 0x80; + writeb(fpga_brdc_data, fpga_brdc); + + writeb(0x3, fpga_enable); + + writeb(0x3, fpga_polarity); + + writeb(0x3, fpga_trigger); + + /* RTC step for the walnut */ + walnut_rtc_base = (void *) WALNUT_RTC_VADDR; + TODC_INIT(TODC_TYPE_DS1743, walnut_rtc_base, walnut_rtc_base, + walnut_rtc_base, 8); + /* Identify the system */ + printk("IBM Walnut port (C) 2000-2002 MontaVista Software, Inc. (source@mvista.com)\n"); +} + +void __init +bios_fixup(struct pci_controller *hose, struct pcil0_regs *pcip) +{ +#ifdef CONFIG_PCI + unsigned int bar_response, bar; + /* + * Expected PCI mapping: + * + * PLB addr PCI memory addr + * --------------------- --------------------- + * 0000'0000 - 7fff'ffff <--- 0000'0000 - 7fff'ffff + * 8000'0000 - Bfff'ffff ---> 8000'0000 - Bfff'ffff + * + * PLB addr PCI io addr + * --------------------- --------------------- + * e800'0000 - e800'ffff ---> 0000'0000 - 0001'0000 + * + * The following code is simplified by assuming that the bootrom + * has been well behaved in following this mapping. + */ + +#ifdef DEBUG + int i; + + printk("ioremap PCLIO_BASE = 0x%x\n", pcip); + printk("PCI bridge regs before fixup \n"); + for (i = 0; i <= 3; i++) { + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma))); + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la))); + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila))); + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha))); + } + printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms))); + printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la))); + printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms))); + printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la))); + +#endif + + /* added for IBM boot rom version 1.15 bios bar changes -AK */ + + /* Disable region first */ + out_le32((void *) &(pcip->pmm[0].ma), 0x00000000); + /* PLB starting addr, PCI: 0x80000000 */ + out_le32((void *) &(pcip->pmm[0].la), 0x80000000); + /* PCI start addr, 0x80000000 */ + out_le32((void *) &(pcip->pmm[0].pcila), PPC405_PCI_MEM_BASE); + /* 512MB range of PLB to PCI */ + out_le32((void *) &(pcip->pmm[0].pciha), 0x00000000); + /* Enable no pre-fetch, enable region */ + out_le32((void *) &(pcip->pmm[0].ma), ((0xffffffff - + (PPC405_PCI_UPPER_MEM - + PPC405_PCI_MEM_BASE)) | 0x01)); + + /* Disable region one */ + out_le32((void *) &(pcip->pmm[1].ma), 0x00000000); + out_le32((void *) &(pcip->pmm[1].la), 0x00000000); + out_le32((void *) &(pcip->pmm[1].pcila), 0x00000000); + out_le32((void *) &(pcip->pmm[1].pciha), 0x00000000); + out_le32((void *) &(pcip->pmm[1].ma), 0x00000000); + out_le32((void *) &(pcip->ptm1ms), 0x00000000); + + /* Disable region two */ + out_le32((void *) &(pcip->pmm[2].ma), 0x00000000); + out_le32((void *) &(pcip->pmm[2].la), 0x00000000); + out_le32((void *) &(pcip->pmm[2].pcila), 0x00000000); + out_le32((void *) &(pcip->pmm[2].pciha), 0x00000000); + out_le32((void *) &(pcip->pmm[2].ma), 0x00000000); + out_le32((void *) &(pcip->ptm2ms), 0x00000000); + + /* Zero config bars */ + for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) { + early_write_config_dword(hose, hose->first_busno, + PCI_FUNC(hose->first_busno), bar, + 0x00000000); + early_read_config_dword(hose, hose->first_busno, + PCI_FUNC(hose->first_busno), bar, + &bar_response); + DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n", + hose->first_busno, PCI_SLOT(hose->first_busno), + PCI_FUNC(hose->first_busno), bar, bar_response); + } + /* end work arround */ + +#ifdef DEBUG + printk("PCI bridge regs after fixup \n"); + for (i = 0; i <= 3; i++) { + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma))); + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la))); + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila))); + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha))); + } + printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms))); + printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la))); + printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms))); + printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la))); + +#endif +#endif +} + +void __init +walnut_map_io(void) +{ + ppc4xx_map_io(); + io_block_mapping(WALNUT_RTC_VADDR, + WALNUT_RTC_PADDR, WALNUT_RTC_SIZE, _PAGE_IO); +} + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + ppc4xx_init(r3, r4, r5, r6, r7); + + ppc_md.setup_arch = walnut_setup_arch; + ppc_md.setup_io_mappings = walnut_map_io; + +#ifdef CONFIG_GEN_RTC + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; +#endif +} diff --git a/arch/ppc/platforms/4xx/walnut.h b/arch/ppc/platforms/4xx/walnut.h new file mode 100644 index 00000000000..04cfbf3696b --- /dev/null +++ b/arch/ppc/platforms/4xx/walnut.h @@ -0,0 +1,72 @@ +/* + * arch/ppc/platforms/4xx/walnut.h + * + * Macros, definitions, and data structures specific to the IBM PowerPC + * 405GP "Walnut" evaluation board. + * + * Authors: Grant Erickson <grant@lcse.umn.edu>, Frank Rowand + * <frank_rowand@mvista.com>, Debbie Chu <debbie_chu@mvista.com> or + * source@mvista.com + * + * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu> + * + * 2000 (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. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_WALNUT_H__ +#define __ASM_WALNUT_H__ + +/* We have a 405GP core */ +#include <platforms/4xx/ibm405gp.h> + +#ifndef __ASSEMBLY__ +/* + * Data structure defining board information maintained by the boot + * ROM on IBM's "Walnut" evaluation board. An effort has been made to + * keep the field names consistent with the 8xx 'bd_t' board info + * structures. + */ + +typedef struct board_info { + unsigned char bi_s_version[4]; /* Version of this structure */ + unsigned char bi_r_version[30]; /* Version of the IBM ROM */ + unsigned int bi_memsize; /* DRAM installed, in bytes */ + unsigned char bi_enetaddr[6]; /* Local Ethernet MAC address */ + unsigned char bi_pci_enetaddr[6]; /* PCI Ethernet MAC address */ + unsigned int bi_intfreq; /* Processor speed, in Hz */ + unsigned int bi_busfreq; /* PLB Bus speed, in Hz */ + unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */ +} bd_t; + +/* Some 4xx parts use a different timebase frequency from the internal clock. +*/ +#define bi_tbfreq bi_intfreq + + +/* Memory map for the IBM "Walnut" 405GP evaluation board. + * Generic 4xx plus RTC. + */ + +extern void *walnut_rtc_base; +#define WALNUT_RTC_PADDR ((uint)0xf0000000) +#define WALNUT_RTC_VADDR WALNUT_RTC_PADDR +#define WALNUT_RTC_SIZE ((uint)8*1024) + +#ifdef CONFIG_PPC405GP_INTERNAL_CLOCK +#define BASE_BAUD 201600 +#else +#define BASE_BAUD 691200 +#endif + +#define WALNUT_PS2_BASE 0xF0100000 +#define WALNUT_FPGA_BASE 0xF0300000 + +#define PPC4xx_MACHINE_NAME "IBM Walnut" + +#endif /* !__ASSEMBLY__ */ +#endif /* __ASM_WALNUT_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/xilinx_ml300.c b/arch/ppc/platforms/4xx/xilinx_ml300.c new file mode 100644 index 00000000000..0b1b77d986b --- /dev/null +++ b/arch/ppc/platforms/4xx/xilinx_ml300.c @@ -0,0 +1,146 @@ +/* + * arch/ppc/platforms/4xx/xilinx_ml300.c + * + * Xilinx ML300 evaluation board initialization + * + * Author: MontaVista Software, Inc. + * source@mvista.com + * + * 2002-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. + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/tty.h> +#include <linux/serial.h> +#include <linux/serial_core.h> +#include <linux/serialP.h> +#include <asm/io.h> +#include <asm/machdep.h> +#include <asm/ocp.h> + +#include <platforms/4xx/virtex-ii_pro.h> /* for NR_SER_PORTS */ + +/* + * As an overview of how the following functions (platform_init, + * ml300_map_io, ml300_setup_arch and ml300_init_IRQ) fit into the + * kernel startup procedure, here's a call tree: + * + * start_here arch/ppc/kernel/head_4xx.S + * early_init arch/ppc/kernel/setup.c + * machine_init arch/ppc/kernel/setup.c + * platform_init this file + * ppc4xx_init arch/ppc/syslib/ppc4xx_setup.c + * parse_bootinfo + * find_bootinfo + * "setup some default ppc_md pointers" + * MMU_init arch/ppc/mm/init.c + * *ppc_md.setup_io_mappings == ml300_map_io this file + * ppc4xx_map_io arch/ppc/syslib/ppc4xx_setup.c + * start_kernel init/main.c + * setup_arch arch/ppc/kernel/setup.c + * #if defined(CONFIG_KGDB) + * *ppc_md.kgdb_map_scc() == gen550_kgdb_map_scc + * #endif + * *ppc_md.setup_arch == ml300_setup_arch this file + * ppc4xx_setup_arch arch/ppc/syslib/ppc4xx_setup.c + * ppc4xx_find_bridges arch/ppc/syslib/ppc405_pci.c + * init_IRQ arch/ppc/kernel/irq.c + * *ppc_md.init_IRQ == ml300_init_IRQ this file + * ppc4xx_init_IRQ arch/ppc/syslib/ppc4xx_setup.c + * ppc4xx_pic_init arch/ppc/syslib/xilinx_pic.c + */ + +#if defined(XPAR_POWER_0_POWERDOWN_BASEADDR) + +static volatile unsigned *powerdown_base = + (volatile unsigned *) XPAR_POWER_0_POWERDOWN_BASEADDR; + +static void +xilinx_power_off(void) +{ + local_irq_disable(); + out_be32(powerdown_base, XPAR_POWER_0_POWERDOWN_VALUE); + while (1) ; +} +#endif + +void __init +ml300_map_io(void) +{ + ppc4xx_map_io(); + +#if defined(XPAR_POWER_0_POWERDOWN_BASEADDR) + powerdown_base = ioremap((unsigned long) powerdown_base, + XPAR_POWER_0_POWERDOWN_HIGHADDR - + XPAR_POWER_0_POWERDOWN_BASEADDR + 1); +#endif +} + +static void __init +ml300_early_serial_map(void) +{ +#ifdef CONFIG_SERIAL_8250 + struct serial_state old_ports[] = { SERIAL_PORT_DFNS }; + struct uart_port port; + int i; + + /* Setup ioremapped serial port access */ + for (i = 0; i < ARRAY_SIZE(old_ports); i++ ) { + memset(&port, 0, sizeof(port)); + port.membase = ioremap((phys_addr_t)(old_ports[i].iomem_base), 16); + port.irq = old_ports[i].irq; + port.uartclk = old_ports[i].baud_base * 16; + port.regshift = old_ports[i].iomem_reg_shift; + port.iotype = SERIAL_IO_MEM; + port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST; + port.line = i; + + if (early_serial_setup(&port) != 0) { + printk("Early serial init of port %d failed\n", i); + } + } +#endif /* CONFIG_SERIAL_8250 */ +} + +void __init +ml300_setup_arch(void) +{ + ppc4xx_setup_arch(); /* calls ppc4xx_find_bridges() */ + + ml300_early_serial_map(); + + /* Identify the system */ + printk(KERN_INFO "Xilinx Virtex-II Pro port\n"); + printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n"); +} + +/* Called after board_setup_irq from ppc4xx_init_IRQ(). */ +void __init +ml300_init_irq(void) +{ + ppc4xx_init_IRQ(); +} + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + ppc4xx_init(r3, r4, r5, r6, r7); + + ppc_md.setup_arch = ml300_setup_arch; + ppc_md.setup_io_mappings = ml300_map_io; + ppc_md.init_IRQ = ml300_init_irq; + +#if defined(XPAR_POWER_0_POWERDOWN_BASEADDR) + ppc_md.power_off = xilinx_power_off; +#endif + +#ifdef CONFIG_KGDB + ppc_md.early_serial_map = ml300_early_serial_map; +#endif +} + diff --git a/arch/ppc/platforms/4xx/xilinx_ml300.h b/arch/ppc/platforms/4xx/xilinx_ml300.h new file mode 100644 index 00000000000..f8c58841233 --- /dev/null +++ b/arch/ppc/platforms/4xx/xilinx_ml300.h @@ -0,0 +1,47 @@ +/* + * arch/ppc/platforms/4xx/xilinx_ml300.h + * + * Include file that defines the Xilinx ML300 evaluation board + * + * Author: MontaVista Software, Inc. + * source@mvista.com + * + * 2002-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. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_XILINX_ML300_H__ +#define __ASM_XILINX_ML300_H__ + +/* ML300 has a Xilinx Virtex-II Pro processor */ +#include <platforms/4xx/virtex-ii_pro.h> + +#ifndef __ASSEMBLY__ + +#include <linux/types.h> + +typedef struct board_info { + unsigned int bi_memsize; /* DRAM installed, in bytes */ + unsigned char bi_enetaddr[6]; /* Local Ethernet MAC address */ + unsigned int bi_intfreq; /* Processor speed, in Hz */ + unsigned int bi_busfreq; /* PLB Bus speed, in Hz */ + unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */ +} bd_t; + +/* Some 4xx parts use a different timebase frequency from the internal clock. +*/ +#define bi_tbfreq bi_intfreq + +#endif /* !__ASSEMBLY__ */ + +/* We don't need anything mapped. Size of zero will accomplish that. */ +#define PPC4xx_ONB_IO_PADDR 0u +#define PPC4xx_ONB_IO_VADDR 0u +#define PPC4xx_ONB_IO_SIZE 0u + +#define PPC4xx_MACHINE_NAME "Xilinx ML300" + +#endif /* __ASM_XILINX_ML300_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/xparameters/xparameters_ml300.h b/arch/ppc/platforms/4xx/xparameters/xparameters_ml300.h new file mode 100644 index 00000000000..97e3f4d4bd5 --- /dev/null +++ b/arch/ppc/platforms/4xx/xparameters/xparameters_ml300.h @@ -0,0 +1,310 @@ +/******************************************************************* +* +* Author: Xilinx, Inc. +* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at your +* option) any later version. +* +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A +* COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS +* ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR STANDARD, +* XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION IS FREE +* FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE FOR OBTAINING +* ANY THIRD PARTY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION. +* XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO +* THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY +* WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM +* CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS FOR A PARTICULAR PURPOSE. +* +* +* Xilinx hardware products are not intended for use in life support +* appliances, devices, or systems. Use in such applications is +* expressly prohibited. +* +* +* (c) Copyright 2002-2004 Xilinx Inc. +* All rights reserved. +* +* +* You should have received a copy of the GNU General Public License along +* with this program; if not, write to the Free Software Foundation, Inc., +* 675 Mass Ave, Cambridge, MA 02139, USA. +* +* Description: Driver parameters +* +*******************************************************************/ + +#define XPAR_XPCI_NUM_INSTANCES 1 +#define XPAR_XPCI_CLOCK_HZ 33333333 +#define XPAR_OPB_PCI_REF_0_DEVICE_ID 0 +#define XPAR_OPB_PCI_REF_0_BASEADDR 0x20000000 +#define XPAR_OPB_PCI_REF_0_HIGHADDR 0x3FFFFFFF +#define XPAR_OPB_PCI_REF_0_CONFIG_ADDR 0x3C000000 +#define XPAR_OPB_PCI_REF_0_CONFIG_DATA 0x3C000004 +#define XPAR_OPB_PCI_REF_0_LCONFIG_ADDR 0x3E000000 +#define XPAR_OPB_PCI_REF_0_MEM_BASEADDR 0x20000000 +#define XPAR_OPB_PCI_REF_0_MEM_HIGHADDR 0x37FFFFFF +#define XPAR_OPB_PCI_REF_0_IO_BASEADDR 0x38000000 +#define XPAR_OPB_PCI_REF_0_IO_HIGHADDR 0x3BFFFFFF + +/******************************************************************/ + +#define XPAR_XEMAC_NUM_INSTANCES 1 +#define XPAR_OPB_ETHERNET_0_BASEADDR 0x60000000 +#define XPAR_OPB_ETHERNET_0_HIGHADDR 0x60003FFF +#define XPAR_OPB_ETHERNET_0_DEVICE_ID 0 +#define XPAR_OPB_ETHERNET_0_ERR_COUNT_EXIST 1 +#define XPAR_OPB_ETHERNET_0_DMA_PRESENT 1 +#define XPAR_OPB_ETHERNET_0_MII_EXIST 1 + +/******************************************************************/ + +#define XPAR_MY_OPB_GPIO_0_DEVICE_ID_0 0 +#define XPAR_MY_OPB_GPIO_0_BASEADDR_0 0x90000000 +#define XPAR_MY_OPB_GPIO_0_HIGHADDR_0 (0x90000000+0x7) +#define XPAR_MY_OPB_GPIO_0_DEVICE_ID_1 1 +#define XPAR_MY_OPB_GPIO_0_BASEADDR_1 (0x90000000+0x8) +#define XPAR_MY_OPB_GPIO_0_HIGHADDR_1 (0x90000000+0x1F) +#define XPAR_XGPIO_NUM_INSTANCES 2 + +/******************************************************************/ + +#define XPAR_XIIC_NUM_INSTANCES 1 +#define XPAR_OPB_IIC_0_BASEADDR 0xA8000000 +#define XPAR_OPB_IIC_0_HIGHADDR 0xA80001FF +#define XPAR_OPB_IIC_0_DEVICE_ID 0 +#define XPAR_OPB_IIC_0_TEN_BIT_ADR 0 + +/******************************************************************/ + +#define XPAR_XUARTNS550_NUM_INSTANCES 2 +#define XPAR_XUARTNS550_CLOCK_HZ 100000000 +#define XPAR_OPB_UART16550_0_BASEADDR 0xA0000000 +#define XPAR_OPB_UART16550_0_HIGHADDR 0xA0001FFF +#define XPAR_OPB_UART16550_0_DEVICE_ID 0 +#define XPAR_OPB_UART16550_1_BASEADDR 0xA0010000 +#define XPAR_OPB_UART16550_1_HIGHADDR 0xA0011FFF +#define XPAR_OPB_UART16550_1_DEVICE_ID 1 + +/******************************************************************/ + +#define XPAR_XSPI_NUM_INSTANCES 1 +#define XPAR_OPB_SPI_0_BASEADDR 0xA4000000 +#define XPAR_OPB_SPI_0_HIGHADDR 0xA400007F +#define XPAR_OPB_SPI_0_DEVICE_ID 0 +#define XPAR_OPB_SPI_0_FIFO_EXIST 1 +#define XPAR_OPB_SPI_0_SPI_SLAVE_ONLY 0 +#define XPAR_OPB_SPI_0_NUM_SS_BITS 1 + +/******************************************************************/ + +#define XPAR_XPS2_NUM_INSTANCES 2 +#define XPAR_OPB_PS2_DUAL_REF_0_DEVICE_ID_0 0 +#define XPAR_OPB_PS2_DUAL_REF_0_BASEADDR_0 0xA9000000 +#define XPAR_OPB_PS2_DUAL_REF_0_HIGHADDR_0 (0xA9000000+0x3F) +#define XPAR_OPB_PS2_DUAL_REF_0_DEVICE_ID_1 1 +#define XPAR_OPB_PS2_DUAL_REF_0_BASEADDR_1 (0xA9000000+0x1000) +#define XPAR_OPB_PS2_DUAL_REF_0_HIGHADDR_1 (0xA9000000+0x103F) + +/******************************************************************/ + +#define XPAR_XTOUCHSCREEN_NUM_INSTANCES 1 +#define XPAR_OPB_TSD_REF_0_BASEADDR 0xAA000000 +#define XPAR_OPB_TSD_REF_0_HIGHADDR 0xAA000007 +#define XPAR_OPB_TSD_REF_0_DEVICE_ID 0 + +/******************************************************************/ + +#define XPAR_OPB_AC97_CONTROLLER_REF_0_BASEADDR 0xA6000000 +#define XPAR_OPB_AC97_CONTROLLER_REF_0_HIGHADDR 0xA60000FF +#define XPAR_OPB_PAR_PORT_REF_0_BASEADDR 0x90010000 +#define XPAR_OPB_PAR_PORT_REF_0_HIGHADDR 0x900100FF +#define XPAR_PLB_DDR_0_BASEADDR 0x00000000 +#define XPAR_PLB_DDR_0_HIGHADDR 0x0FFFFFFF + +/******************************************************************/ + +#define XPAR_XINTC_HAS_IPR 1 +#define XPAR_INTC_MAX_NUM_INTR_INPUTS 18 +#define XPAR_XINTC_USE_DCR 0 +#define XPAR_XINTC_NUM_INSTANCES 1 +#define XPAR_DCR_INTC_0_BASEADDR 0xD0000FC0 +#define XPAR_DCR_INTC_0_HIGHADDR 0xD0000FDF +#define XPAR_DCR_INTC_0_DEVICE_ID 0 +#define XPAR_DCR_INTC_0_KIND_OF_INTR 0x00038000 + +/******************************************************************/ + +#define XPAR_DCR_INTC_0_MISC_LOGIC_0_PHY_MII_INT_INTR 0 +#define XPAR_DCR_INTC_0_OPB_ETHERNET_0_IP2INTC_IRPT_INTR 1 +#define XPAR_DCR_INTC_0_MISC_LOGIC_0_IIC_TEMP_CRIT_INTR 2 +#define XPAR_DCR_INTC_0_MISC_LOGIC_0_IIC_IRQ_INTR 3 +#define XPAR_DCR_INTC_0_OPB_IIC_0_IP2INTC_IRPT_INTR 4 +#define XPAR_DCR_INTC_0_OPB_SYSACE_0_SYSACE_IRQ_INTR 5 +#define XPAR_DCR_INTC_0_OPB_UART16550_0_IP2INTC_IRPT_INTR 6 +#define XPAR_DCR_INTC_0_OPB_UART16550_1_IP2INTC_IRPT_INTR 7 +#define XPAR_DCR_INTC_0_OPB_PS2_DUAL_REF_0_SYS_INTR1_INTR 8 +#define XPAR_DCR_INTC_0_OPB_PS2_DUAL_REF_0_SYS_INTR2_INTR 9 +#define XPAR_DCR_INTC_0_OPB_SPI_0_IP2INTC_IRPT_INTR 10 +#define XPAR_DCR_INTC_0_OPB_TSD_REF_0_INTR_INTR 11 +#define XPAR_DCR_INTC_0_OPB_AC97_CONTROLLER_REF_0_PLAYBACK_INTERRUPT_INTR 12 +#define XPAR_DCR_INTC_0_OPB_AC97_CONTROLLER_REF_0_RECORD_INTERRUPT_INTR 13 +#define XPAR_DCR_INTC_0_OPB_PCI_REF_0_INTR_OUT_INTR 14 +#define XPAR_DCR_INTC_0_PLB2OPB_BRIDGE_0_BUS_ERROR_DET_INTR 15 +#define XPAR_DCR_INTC_0_PLB_V34_0_BUS_ERROR_DET_INTR 16 +#define XPAR_DCR_INTC_0_OPB2PLB_BRIDGE_0_BUS_ERROR_DET_INTR 17 + +/******************************************************************/ + +#define XPAR_XTFT_NUM_INSTANCES 1 +#define XPAR_PLB_TFT_CNTLR_REF_0_DCR_BASEADDR 0xD0000200 +#define XPAR_PLB_TFT_CNTLR_REF_0_DCR_HIGHADDR 0xD0000207 +#define XPAR_PLB_TFT_CNTLR_REF_0_DEVICE_ID 0 + +/******************************************************************/ + +#define XPAR_XSYSACE_MEM_WIDTH 8 +#define XPAR_XSYSACE_NUM_INSTANCES 1 +#define XPAR_OPB_SYSACE_0_BASEADDR 0xCF000000 +#define XPAR_OPB_SYSACE_0_HIGHADDR 0xCF0001FF +#define XPAR_OPB_SYSACE_0_DEVICE_ID 0 +#define XPAR_OPB_SYSACE_0_MEM_WIDTH 8 + +/******************************************************************/ + +#define XPAR_CPU_PPC405_CORE_CLOCK_FREQ_HZ 300000000 + +/******************************************************************/ + +/******************************************************************/ + +/* Linux Redefines */ + +/******************************************************************/ + +#define XPAR_UARTNS550_0_BASEADDR (XPAR_OPB_UART16550_0_BASEADDR+0x1000) +#define XPAR_UARTNS550_0_HIGHADDR XPAR_OPB_UART16550_0_HIGHADDR +#define XPAR_UARTNS550_0_CLOCK_FREQ_HZ XPAR_XUARTNS550_CLOCK_HZ +#define XPAR_UARTNS550_0_DEVICE_ID XPAR_OPB_UART16550_0_DEVICE_ID +#define XPAR_UARTNS550_1_BASEADDR (XPAR_OPB_UART16550_1_BASEADDR+0x1000) +#define XPAR_UARTNS550_1_HIGHADDR XPAR_OPB_UART16550_1_HIGHADDR +#define XPAR_UARTNS550_1_CLOCK_FREQ_HZ XPAR_XUARTNS550_CLOCK_HZ +#define XPAR_UARTNS550_1_DEVICE_ID XPAR_OPB_UART16550_1_DEVICE_ID + +/******************************************************************/ + +#define XPAR_GPIO_0_BASEADDR XPAR_MY_OPB_GPIO_0_BASEADDR_0 +#define XPAR_GPIO_0_HIGHADDR XPAR_MY_OPB_GPIO_0_HIGHADDR_0 +#define XPAR_GPIO_0_DEVICE_ID XPAR_MY_OPB_GPIO_0_DEVICE_ID_0 +#define XPAR_GPIO_1_BASEADDR XPAR_MY_OPB_GPIO_0_BASEADDR_1 +#define XPAR_GPIO_1_HIGHADDR XPAR_MY_OPB_GPIO_0_HIGHADDR_1 +#define XPAR_GPIO_1_DEVICE_ID XPAR_MY_OPB_GPIO_0_DEVICE_ID_1 + +/******************************************************************/ + +#define XPAR_IIC_0_BASEADDR XPAR_OPB_IIC_0_BASEADDR +#define XPAR_IIC_0_HIGHADDR XPAR_OPB_IIC_0_HIGHADDR +#define XPAR_IIC_0_TEN_BIT_ADR XPAR_OPB_IIC_0_TEN_BIT_ADR +#define XPAR_IIC_0_DEVICE_ID XPAR_OPB_IIC_0_DEVICE_ID + +/******************************************************************/ + +#define XPAR_SYSACE_0_BASEADDR XPAR_OPB_SYSACE_0_BASEADDR +#define XPAR_SYSACE_0_HIGHADDR XPAR_OPB_SYSACE_0_HIGHADDR +#define XPAR_SYSACE_0_DEVICE_ID XPAR_OPB_SYSACE_0_DEVICE_ID + +/******************************************************************/ + +#define XPAR_INTC_0_BASEADDR XPAR_DCR_INTC_0_BASEADDR +#define XPAR_INTC_0_HIGHADDR XPAR_DCR_INTC_0_HIGHADDR +#define XPAR_INTC_0_KIND_OF_INTR XPAR_DCR_INTC_0_KIND_OF_INTR +#define XPAR_INTC_0_DEVICE_ID XPAR_DCR_INTC_0_DEVICE_ID + +/******************************************************************/ + +#define XPAR_INTC_0_EMAC_0_VEC_ID XPAR_DCR_INTC_0_OPB_ETHERNET_0_IP2INTC_IRPT_INTR +#define XPAR_INTC_0_IIC_0_VEC_ID XPAR_DCR_INTC_0_OPB_IIC_0_IP2INTC_IRPT_INTR +#define XPAR_INTC_0_SYSACE_0_VEC_ID XPAR_DCR_INTC_0_OPB_SYSACE_0_SYSACE_IRQ_INTR +#define XPAR_INTC_0_UARTNS550_0_VEC_ID XPAR_DCR_INTC_0_OPB_UART16550_0_IP2INTC_IRPT_INTR +#define XPAR_INTC_0_UARTNS550_1_VEC_ID XPAR_DCR_INTC_0_OPB_UART16550_1_IP2INTC_IRPT_INTR +#define XPAR_INTC_0_PS2_0_VEC_ID XPAR_DCR_INTC_0_OPB_PS2_DUAL_REF_0_SYS_INTR1_INTR +#define XPAR_INTC_0_PS2_1_VEC_ID XPAR_DCR_INTC_0_OPB_PS2_DUAL_REF_0_SYS_INTR2_INTR +#define XPAR_INTC_0_SPI_0_VEC_ID XPAR_DCR_INTC_0_OPB_SPI_0_IP2INTC_IRPT_INTR +#define XPAR_INTC_0_TOUCHSCREEN_0_VEC_ID XPAR_DCR_INTC_0_OPB_TSD_REF_0_INTR_INTR +#define XPAR_INTC_0_PCI_0_VEC_ID_A XPAR_DCR_INTC_0_OPB_PCI_REF_0_INTR_OUT_INTR +#define XPAR_INTC_0_PCI_0_VEC_ID_B XPAR_DCR_INTC_0_OPB_PCI_REF_0_INTR_OUT_INTR +#define XPAR_INTC_0_PCI_0_VEC_ID_C XPAR_DCR_INTC_0_OPB_PCI_REF_0_INTR_OUT_INTR +#define XPAR_INTC_0_PCI_0_VEC_ID_D XPAR_DCR_INTC_0_OPB_PCI_REF_0_INTR_OUT_INTR + +/******************************************************************/ + +#define XPAR_EMAC_0_BASEADDR XPAR_OPB_ETHERNET_0_BASEADDR +#define XPAR_EMAC_0_HIGHADDR XPAR_OPB_ETHERNET_0_HIGHADDR +#define XPAR_EMAC_0_DMA_PRESENT XPAR_OPB_ETHERNET_0_DMA_PRESENT +#define XPAR_EMAC_0_MII_EXIST XPAR_OPB_ETHERNET_0_MII_EXIST +#define XPAR_EMAC_0_ERR_COUNT_EXIST XPAR_OPB_ETHERNET_0_ERR_COUNT_EXIST +#define XPAR_EMAC_0_DEVICE_ID XPAR_OPB_ETHERNET_0_DEVICE_ID + +/******************************************************************/ + +#define XPAR_SPI_0_BASEADDR XPAR_OPB_SPI_0_BASEADDR +#define XPAR_SPI_0_HIGHADDR XPAR_OPB_SPI_0_HIGHADDR +#define XPAR_SPI_0_DEVICE_ID XPAR_OPB_SPI_0_DEVICE_ID + +/******************************************************************/ + +#define XPAR_TOUCHSCREEN_0_BASEADDR XPAR_OPB_TSD_REF_0_BASEADDR +#define XPAR_TOUCHSCREEN_0_HIGHADDR XPAR_OPB_TSD_REF_0_HIGHADDR +#define XPAR_TOUCHSCREEN_0_DEVICE_ID XPAR_OPB_TSD_REF_0_DEVICE_ID + +/******************************************************************/ + +#define XPAR_TFT_0_BASEADDR XPAR_PLB_TFT_CNTLR_REF_0_DCR_BASEADDR + +/******************************************************************/ + +#define XPAR_PCI_0_BASEADDR XPAR_OPB_PCI_REF_0_BASEADDR +#define XPAR_PCI_0_HIGHADDR XPAR_OPB_PCI_REF_0_HIGHADDR +#define XPAR_PCI_0_CONFIG_ADDR XPAR_OPB_PCI_REF_0_CONFIG_ADDR +#define XPAR_PCI_0_CONFIG_DATA XPAR_OPB_PCI_REF_0_CONFIG_DATA +#define XPAR_PCI_0_LCONFIG_ADDR XPAR_OPB_PCI_REF_0_LCONFIG_ADDR +#define XPAR_PCI_0_MEM_BASEADDR XPAR_OPB_PCI_REF_0_MEM_BASEADDR +#define XPAR_PCI_0_MEM_HIGHADDR XPAR_OPB_PCI_REF_0_MEM_HIGHADDR +#define XPAR_PCI_0_IO_BASEADDR XPAR_OPB_PCI_REF_0_IO_BASEADDR +#define XPAR_PCI_0_IO_HIGHADDR XPAR_OPB_PCI_REF_0_IO_HIGHADDR +#define XPAR_PCI_0_CLOCK_FREQ_HZ XPAR_XPCI_CLOCK_HZ +#define XPAR_PCI_0_DEVICE_ID XPAR_OPB_PCI_REF_0_DEVICE_ID + +/******************************************************************/ + +#define XPAR_PS2_0_BASEADDR XPAR_OPB_PS2_DUAL_REF_0_BASEADDR_0 +#define XPAR_PS2_0_HIGHADDR XPAR_OPB_PS2_DUAL_REF_0_HIGHADDR_0 +#define XPAR_PS2_0_DEVICE_ID XPAR_OPB_PS2_DUAL_REF_0_DEVICE_ID_0 +#define XPAR_PS2_1_BASEADDR XPAR_OPB_PS2_DUAL_REF_0_BASEADDR_1 +#define XPAR_PS2_1_HIGHADDR XPAR_OPB_PS2_DUAL_REF_0_HIGHADDR_1 +#define XPAR_PS2_1_DEVICE_ID XPAR_OPB_PS2_DUAL_REF_0_DEVICE_ID_1 + +/******************************************************************/ + +#define XPAR_PLB_CLOCK_FREQ_HZ 100000000 +#define XPAR_CORE_CLOCK_FREQ_HZ XPAR_CPU_PPC405_CORE_CLOCK_FREQ_HZ +#define XPAR_DDR_0_SIZE 0x08000000 + +/******************************************************************/ + +#define XPAR_PERSISTENT_0_IIC_0_BASEADDR 0x00000400 +#define XPAR_PERSISTENT_0_IIC_0_HIGHADDR 0x000007FF +#define XPAR_PERSISTENT_0_IIC_0_EEPROMADDR 0xA0 + +/******************************************************************/ + +#define XPAR_POWER_0_POWERDOWN_BASEADDR 0x90000004 +#define XPAR_POWER_0_POWERDOWN_HIGHADDR 0x90000007 +#define XPAR_POWER_0_POWERDOWN_VALUE 0xFF + +/******************************************************************/ diff --git a/arch/ppc/platforms/83xx/Makefile b/arch/ppc/platforms/83xx/Makefile new file mode 100644 index 00000000000..eb55341d6a1 --- /dev/null +++ b/arch/ppc/platforms/83xx/Makefile @@ -0,0 +1,4 @@ +# +# Makefile for the PowerPC 83xx linux kernel. +# +obj-$(CONFIG_MPC834x_SYS) += mpc834x_sys.o diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.c b/arch/ppc/platforms/83xx/mpc834x_sys.c new file mode 100644 index 00000000000..b3b0f51979d --- /dev/null +++ b/arch/ppc/platforms/83xx/mpc834x_sys.c @@ -0,0 +1,289 @@ +/* + * arch/ppc/platforms/83xx/mpc834x_sys.c + * + * MPC834x SYS board specific routines + * + * Maintainer: Kumar Gala <kumar.gala@freescale.com> + * + * Copyright 2005 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/major.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/seq_file.h> +#include <linux/root_dev.h> +#include <linux/serial.h> +#include <linux/tty.h> /* for linux/serial_core.h */ +#include <linux/serial_core.h> +#include <linux/initrd.h> +#include <linux/module.h> +#include <linux/fsl_devices.h> + +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/atomic.h> +#include <asm/time.h> +#include <asm/io.h> +#include <asm/machdep.h> +#include <asm/prom.h> +#include <asm/ipic.h> +#include <asm/bootinfo.h> +#include <asm/pci-bridge.h> +#include <asm/mpc83xx.h> +#include <asm/irq.h> +#include <asm/kgdb.h> +#include <asm/ppc_sys.h> +#include <mm/mmu_decl.h> + +#include <syslib/ppc83xx_setup.h> + +#ifndef CONFIG_PCI +unsigned long isa_io_base = 0; +unsigned long isa_mem_base = 0; +#endif + +extern unsigned long total_memory; /* in mm/init */ + +unsigned char __res[sizeof (bd_t)]; + +#ifdef CONFIG_PCI +#error "PCI is not supported" +/* NEED mpc83xx_map_irq & mpc83xx_exclude_device + see platforms/85xx/mpc85xx_ads_common.c */ +#endif /* CONFIG_PCI */ + +/* ************************************************************************ + * + * Setup the architecture + * + */ +static void __init +mpc834x_sys_setup_arch(void) +{ + bd_t *binfo = (bd_t *) __res; + unsigned int freq; + struct gianfar_platform_data *pdata; + + /* get the core frequency */ + freq = binfo->bi_intfreq; + + /* Set loops_per_jiffy to a half-way reasonable value, + for use until calibrate_delay gets called. */ + loops_per_jiffy = freq / HZ; + +#ifdef CONFIG_PCI + /* setup PCI host bridges */ + mpc83xx_sys_setup_hose(); +#endif + mpc83xx_early_serial_map(); + + /* setup the board related information for the enet controllers */ + pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC83xx_TSEC1); + pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; + pdata->interruptPHY = MPC83xx_IRQ_EXT1; + pdata->phyid = 0; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); + + pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC83xx_TSEC2); + pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; + pdata->interruptPHY = MPC83xx_IRQ_EXT2; + pdata->phyid = 1; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_HDA1; +#endif +} + +static void __init +mpc834x_sys_map_io(void) +{ + /* we steal the lowest ioremap addr for virt space */ + io_block_mapping(VIRT_IMMRBAR, immrbar, 1024*1024, _PAGE_IO); + io_block_mapping(BCSR_VIRT_ADDR, BCSR_PHYS_ADDR, BCSR_SIZE, _PAGE_IO); +} + +int +mpc834x_sys_show_cpuinfo(struct seq_file *m) +{ + uint pvid, svid, phid1; + bd_t *binfo = (bd_t *) __res; + unsigned int freq; + + /* get the core frequency */ + freq = binfo->bi_intfreq; + + pvid = mfspr(SPRN_PVR); + svid = mfspr(SPRN_SVR); + + seq_printf(m, "Vendor\t\t: Freescale Inc.\n"); + seq_printf(m, "Machine\t\t: mpc%s sys\n", cur_ppc_sys_spec->ppc_sys_name); + seq_printf(m, "core clock\t: %d MHz\n" + "bus clock\t: %d MHz\n", + (int)(binfo->bi_intfreq / 1000000), + (int)(binfo->bi_busfreq / 1000000)); + seq_printf(m, "PVR\t\t: 0x%x\n", pvid); + seq_printf(m, "SVR\t\t: 0x%x\n", svid); + + /* Display cpu Pll setting */ + phid1 = mfspr(SPRN_HID1); + seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); + + /* Display the amount of memory */ + seq_printf(m, "Memory\t\t: %d MB\n", (int)(binfo->bi_memsize / (1024 * 1024))); + + return 0; +} + + +void __init +mpc834x_sys_init_IRQ(void) +{ + bd_t *binfo = (bd_t *) __res; + + u8 senses[8] = { + 0, /* EXT 0 */ + IRQ_SENSE_LEVEL, /* EXT 1 */ + IRQ_SENSE_LEVEL, /* EXT 2 */ + 0, /* EXT 3 */ + 0, /* EXT 4 */ + 0, /* EXT 5 */ + 0, /* EXT 6 */ + 0, /* EXT 7 */ + }; + + ipic_init(binfo->bi_immr_base + 0x00700, 0, MPC83xx_IPIC_IRQ_OFFSET, senses, 8); + + /* Initialize the default interrupt mapping priorities, + * in case the boot rom changed something on us. + */ + ipic_set_default_priority(); +} + +static __inline__ void +mpc834x_sys_set_bat(void) +{ + /* we steal the lowest ioremap addr for virt space */ + mb(); + mtspr(SPRN_DBAT1U, VIRT_IMMRBAR | 0x1e); + mtspr(SPRN_DBAT1L, immrbar | 0x2a); + mb(); +} + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + bd_t *binfo = (bd_t *) __res; + + /* parse_bootinfo must always be called first */ + parse_bootinfo(find_bootinfo()); + + /* + * If we were passed in a board information, copy it into the + * residual data area. + */ + if (r3) { + memcpy((void *) __res, (void *) (r3 + KERNELBASE), + sizeof (bd_t)); + } + +#if defined(CONFIG_BLK_DEV_INITRD) + /* + * If the init RAM disk has been configured in, and there's a valid + * starting address for it, set it up. + */ + if (r4) { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif /* CONFIG_BLK_DEV_INITRD */ + + /* Copy the kernel command line arguments to a safe place. */ + if (r6) { + *(char *) (r7 + KERNELBASE) = 0; + strcpy(cmd_line, (char *) (r6 + KERNELBASE)); + } + + immrbar = binfo->bi_immr_base; + + mpc834x_sys_set_bat(); + +#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG) + { + struct uart_port p; + + memset(&p, 0, sizeof (p)); + p.iotype = SERIAL_IO_MEM; + p.membase = (unsigned char __iomem *)(VIRT_IMMRBAR + 0x4500); + p.uartclk = binfo->bi_busfreq; + + gen550_init(0, &p); + + memset(&p, 0, sizeof (p)); + p.iotype = SERIAL_IO_MEM; + p.membase = (unsigned char __iomem *)(VIRT_IMMRBAR + 0x4600); + p.uartclk = binfo->bi_busfreq; + + gen550_init(1, &p); + } +#endif + + identify_ppc_sys_by_id(mfspr(SPRN_SVR)); + + /* setup the PowerPC module struct */ + ppc_md.setup_arch = mpc834x_sys_setup_arch; + ppc_md.show_cpuinfo = mpc834x_sys_show_cpuinfo; + + ppc_md.init_IRQ = mpc834x_sys_init_IRQ; + ppc_md.get_irq = ipic_get_irq; + + ppc_md.restart = mpc83xx_restart; + ppc_md.power_off = mpc83xx_power_off; + ppc_md.halt = mpc83xx_halt; + + ppc_md.find_end_of_memory = mpc83xx_find_end_of_memory; + ppc_md.setup_io_mappings = mpc834x_sys_map_io; + + ppc_md.time_init = mpc83xx_time_init; + ppc_md.set_rtc_time = NULL; + ppc_md.get_rtc_time = NULL; + ppc_md.calibrate_decr = mpc83xx_calibrate_decr; + + ppc_md.early_serial_map = mpc83xx_early_serial_map; +#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG) + ppc_md.progress = gen550_progress; +#endif /* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */ + + if (ppc_md.progress) + ppc_md.progress("mpc834x_sys_init(): exit", 0); + + return; +} diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.h b/arch/ppc/platforms/83xx/mpc834x_sys.h new file mode 100644 index 00000000000..f4d055ae19c --- /dev/null +++ b/arch/ppc/platforms/83xx/mpc834x_sys.h @@ -0,0 +1,51 @@ +/* + * arch/ppc/platforms/83xx/mpc834x_sys.h + * + * MPC834X SYS common board definitions + * + * Maintainer: Kumar Gala <kumar.gala@freescale.com> + * + * Copyright 2005 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __MACH_MPC83XX_SYS_H__ +#define __MACH_MPC83XX_SYS_H__ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/seq_file.h> +#include <syslib/ppc83xx_setup.h> +#include <asm/ppcboot.h> + +#define VIRT_IMMRBAR ((uint)0xfe000000) + +#define BCSR_PHYS_ADDR ((uint)0xf8000000) +#define BCSR_VIRT_ADDR ((uint)0xfe100000) +#define BCSR_SIZE ((uint)(32 * 1024)) + +#ifdef CONFIG_PCI +/* PCI interrupt controller */ +#define PIRQA MPC83xx_IRQ_IRQ4 +#define PIRQB MPC83xx_IRQ_IRQ5 +#define PIRQC MPC83xx_IRQ_IRQ6 +#define PIRQD MPC83xx_IRQ_IRQ7 + +#define MPC834x_SYS_PCI1_LOWER_IO 0x00000000 +#define MPC834x_SYS_PCI1_UPPER_IO 0x00ffffff + +#define MPC834x_SYS_PCI1_LOWER_MEM 0x80000000 +#define MPC834x_SYS_PCI1_UPPER_MEM 0x9fffffff + +#define MPC834x_SYS_PCI1_IO_BASE 0xe2000000 +#define MPC834x_SYS_PCI1_MEM_OFFSET 0x00000000 + +#define MPC834x_SYS_PCI1_IO_SIZE 0x01000000 +#endif /* CONFIG_PCI */ + +#endif /* __MACH_MPC83XX_SYS_H__ */ diff --git a/arch/ppc/platforms/85xx/Kconfig b/arch/ppc/platforms/85xx/Kconfig new file mode 100644 index 00000000000..ff92e38e7da --- /dev/null +++ b/arch/ppc/platforms/85xx/Kconfig @@ -0,0 +1,76 @@ +config 85xx + bool + depends on E500 + default y + +config PPC_INDIRECT_PCI_BE + bool + depends on 85xx + default y + +menu "Freescale 85xx options" + depends on E500 + +choice + prompt "Machine Type" + depends on 85xx + default MPC8540_ADS + +config MPC8540_ADS + bool "Freescale MPC8540 ADS" + help + This option enables support for the MPC 8540 ADS evaluation board. + +config MPC8555_CDS + bool "Freescale MPC8555 CDS" + help + This option enablese support for the MPC8555 CDS evaluation board. + +config MPC8560_ADS + bool "Freescale MPC8560 ADS" + help + This option enables support for the MPC 8560 ADS evaluation board. + +config SBC8560 + bool "WindRiver PowerQUICC III SBC8560" + help + This option enables support for the WindRiver PowerQUICC III + SBC8560 board. + +config STX_GP3 + bool "Silicon Turnkey Express GP3" + help + This option enables support for the Silicon Turnkey Express GP3 + board. + +endchoice + +# It's often necessary to know the specific 85xx processor type. +# Fortunately, it is implied (so far) from the board type, so we +# don't need to ask more redundant questions. +config MPC8540 + bool + depends on MPC8540_ADS + default y + +config MPC8555 + bool + depends on MPC8555_CDS + default y + +config MPC8560 + bool + depends on SBC8560 || MPC8560_ADS || STX_GP3 + default y + +config 85xx_PCI2 + bool "Supprt for 2nd PCI host controller" + depends on MPC8555_CDS + default y + +config PPC_GEN550 + bool + depends on MPC8540 || SBC8560 || MPC8555 + default y + +endmenu diff --git a/arch/ppc/platforms/85xx/Makefile b/arch/ppc/platforms/85xx/Makefile new file mode 100644 index 00000000000..854fbd298ba --- /dev/null +++ b/arch/ppc/platforms/85xx/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the PowerPC 85xx linux kernel. +# +obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads_common.o mpc8540_ads.o +obj-$(CONFIG_MPC8555_CDS) += mpc85xx_cds_common.o +obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads_common.o mpc8560_ads.o +obj-$(CONFIG_SBC8560) += sbc85xx.o sbc8560.o +obj-$(CONFIG_STX_GP3) += stx_gp3.o diff --git a/arch/ppc/platforms/85xx/mpc8540_ads.c b/arch/ppc/platforms/85xx/mpc8540_ads.c new file mode 100644 index 00000000000..4d857d6d633 --- /dev/null +++ b/arch/ppc/platforms/85xx/mpc8540_ads.c @@ -0,0 +1,218 @@ +/* + * arch/ppc/platforms/85xx/mpc8540_ads.c + * + * MPC8540ADS board specific routines + * + * Maintainer: Kumar Gala <kumar.gala@freescale.com> + * + * Copyright 2004 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/major.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/seq_file.h> +#include <linux/root_dev.h> +#include <linux/serial.h> +#include <linux/tty.h> /* for linux/serial_core.h */ +#include <linux/serial_core.h> +#include <linux/initrd.h> +#include <linux/module.h> +#include <linux/fsl_devices.h> + +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/atomic.h> +#include <asm/time.h> +#include <asm/io.h> +#include <asm/machdep.h> +#include <asm/prom.h> +#include <asm/open_pic.h> +#include <asm/bootinfo.h> +#include <asm/pci-bridge.h> +#include <asm/mpc85xx.h> +#include <asm/irq.h> +#include <asm/immap_85xx.h> +#include <asm/kgdb.h> +#include <asm/ppc_sys.h> +#include <mm/mmu_decl.h> + +#include <syslib/ppc85xx_setup.h> + +/* ************************************************************************ + * + * Setup the architecture + * + */ +static void __init +mpc8540ads_setup_arch(void) +{ + bd_t *binfo = (bd_t *) __res; + unsigned int freq; + struct gianfar_platform_data *pdata; + + /* get the core frequency */ + freq = binfo->bi_intfreq; + + if (ppc_md.progress) + ppc_md.progress("mpc8540ads_setup_arch()", 0); + + /* Set loops_per_jiffy to a half-way reasonable value, + for use until calibrate_delay gets called. */ + loops_per_jiffy = freq / HZ; + +#ifdef CONFIG_PCI + /* setup PCI host bridges */ + mpc85xx_setup_hose(); +#endif + +#ifdef CONFIG_SERIAL_8250 + mpc85xx_early_serial_map(); +#endif + +#ifdef CONFIG_SERIAL_TEXT_DEBUG + /* Invalidate the entry we stole earlier the serial ports + * should be properly mapped */ + invalidate_tlbcam_entry(NUM_TLBCAMS - 1); +#endif + + /* setup the board related information for the enet controllers */ + pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); + pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; + pdata->interruptPHY = MPC85xx_IRQ_EXT5; + pdata->phyid = 0; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); + + pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2); + pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; + pdata->interruptPHY = MPC85xx_IRQ_EXT5; + pdata->phyid = 1; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); + + pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_FEC); + pdata->board_flags = 0; + pdata->interruptPHY = MPC85xx_IRQ_EXT5; + pdata->phyid = 3; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enet2addr, 6); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_HDA1; +#endif +} + +/* ************************************************************************ */ +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + /* parse_bootinfo must always be called first */ + parse_bootinfo(find_bootinfo()); + + /* + * If we were passed in a board information, copy it into the + * residual data area. + */ + if (r3) { + memcpy((void *) __res, (void *) (r3 + KERNELBASE), + sizeof (bd_t)); + } +#ifdef CONFIG_SERIAL_TEXT_DEBUG + { + bd_t *binfo = (bd_t *) __res; + struct uart_port p; + + /* Use the last TLB entry to map CCSRBAR to allow access to DUART regs */ + settlbcam(NUM_TLBCAMS - 1, binfo->bi_immr_base, + binfo->bi_immr_base, MPC85xx_CCSRBAR_SIZE, _PAGE_IO, 0); + + memset(&p, 0, sizeof (p)); + p.iotype = SERIAL_IO_MEM; + p.membase = (void *) binfo->bi_immr_base + MPC85xx_UART0_OFFSET; + p.uartclk = binfo->bi_busfreq; + + gen550_init(0, &p); + + memset(&p, 0, sizeof (p)); + p.iotype = SERIAL_IO_MEM; + p.membase = (void *) binfo->bi_immr_base + MPC85xx_UART1_OFFSET; + p.uartclk = binfo->bi_busfreq; + + gen550_init(1, &p); + } +#endif + +#if defined(CONFIG_BLK_DEV_INITRD) + /* + * If the init RAM disk has been configured in, and there's a valid + * starting address for it, set it up. + */ + if (r4) { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif /* CONFIG_BLK_DEV_INITRD */ + + /* Copy the kernel command line arguments to a safe place. */ + + if (r6) { + *(char *) (r7 + KERNELBASE) = 0; + strcpy(cmd_line, (char *) (r6 + KERNELBASE)); + } + + identify_ppc_sys_by_id(mfspr(SPRN_SVR)); + + /* setup the PowerPC module struct */ + ppc_md.setup_arch = mpc8540ads_setup_arch; + ppc_md.show_cpuinfo = mpc85xx_ads_show_cpuinfo; + + ppc_md.init_IRQ = mpc85xx_ads_init_IRQ; + ppc_md.get_irq = openpic_get_irq; + + ppc_md.restart = mpc85xx_restart; + ppc_md.power_off = mpc85xx_power_off; + ppc_md.halt = mpc85xx_halt; + + ppc_md.find_end_of_memory = mpc85xx_find_end_of_memory; + + ppc_md.time_init = NULL; + ppc_md.set_rtc_time = NULL; + ppc_md.get_rtc_time = NULL; + ppc_md.calibrate_decr = mpc85xx_calibrate_decr; + +#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG) + ppc_md.progress = gen550_progress; +#endif /* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */ + + if (ppc_md.progress) + ppc_md.progress("mpc8540ads_init(): exit", 0); + + return; +} diff --git a/arch/ppc/platforms/85xx/mpc8540_ads.h b/arch/ppc/platforms/85xx/mpc8540_ads.h new file mode 100644 index 00000000000..3d05d7c4a93 --- /dev/null +++ b/arch/ppc/platforms/85xx/mpc8540_ads.h @@ -0,0 +1,25 @@ +/* + * arch/ppc/platforms/85xx/mpc8540_ads.h + * + * MPC8540ADS board definitions + * + * Maintainer: Kumar Gala <kumar.gala@freescale.com> + * + * Copyright 2004 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __MACH_MPC8540ADS_H__ +#define __MACH_MPC8540ADS_H__ + +#include <linux/config.h> +#include <linux/initrd.h> +#include <syslib/ppc85xx_setup.h> +#include <platforms/85xx/mpc85xx_ads_common.h> + +#endif /* __MACH_MPC8540ADS_H__ */ diff --git a/arch/ppc/platforms/85xx/mpc8555_cds.h b/arch/ppc/platforms/85xx/mpc8555_cds.h new file mode 100644 index 00000000000..e0e75568bc5 --- /dev/null +++ b/arch/ppc/platforms/85xx/mpc8555_cds.h @@ -0,0 +1,26 @@ +/* + * arch/ppc/platforms/mpc8555_cds.h + * + * MPC8555CDS board definitions + * + * Maintainer: Kumar Gala <kumar.gala@freescale.com> + * + * Copyright 2004 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __MACH_MPC8555CDS_H__ +#define __MACH_MPC8555CDS_H__ + +#include <linux/config.h> +#include <syslib/ppc85xx_setup.h> +#include <platforms/85xx/mpc85xx_cds_common.h> + +#define CPM_MAP_ADDR (CCSRBAR + MPC85xx_CPM_OFFSET) + +#endif /* __MACH_MPC8555CDS_H__ */ diff --git a/arch/ppc/platforms/85xx/mpc8560_ads.c b/arch/ppc/platforms/85xx/mpc8560_ads.c new file mode 100644 index 00000000000..761b8c7b25d --- /dev/null +++ b/arch/ppc/platforms/85xx/mpc8560_ads.c @@ -0,0 +1,210 @@ +/* + * arch/ppc/platforms/85xx/mpc8560_ads.c + * + * MPC8560ADS board specific routines + * + * Maintainer: Kumar Gala <kumar.gala@freescale.com> + * + * Copyright 2004 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/major.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/seq_file.h> +#include <linux/root_dev.h> +#include <linux/serial.h> +#include <linux/tty.h> /* for linux/serial_core.h */ +#include <linux/serial_core.h> +#include <linux/initrd.h> +#include <linux/module.h> +#include <linux/fsl_devices.h> + +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/atomic.h> +#include <asm/time.h> +#include <asm/io.h> +#include <asm/machdep.h> +#include <asm/prom.h> +#include <asm/open_pic.h> +#include <asm/bootinfo.h> +#include <asm/pci-bridge.h> +#include <asm/mpc85xx.h> +#include <asm/irq.h> +#include <asm/immap_85xx.h> +#include <asm/kgdb.h> +#include <asm/ppc_sys.h> +#include <asm/cpm2.h> +#include <mm/mmu_decl.h> + +#include <syslib/cpm2_pic.h> +#include <syslib/ppc85xx_common.h> +#include <syslib/ppc85xx_setup.h> + +extern void cpm2_reset(void); + +/* ************************************************************************ + * + * Setup the architecture + * + */ + +static void __init +mpc8560ads_setup_arch(void) +{ + bd_t *binfo = (bd_t *) __res; + unsigned int freq; + struct gianfar_platform_data *pdata; + + cpm2_reset(); + + /* get the core frequency */ + freq = binfo->bi_intfreq; + + if (ppc_md.progress) + ppc_md.progress("mpc8560ads_setup_arch()", 0); + + /* Set loops_per_jiffy to a half-way reasonable value, + for use until calibrate_delay gets called. */ + loops_per_jiffy = freq / HZ; + +#ifdef CONFIG_PCI + /* setup PCI host bridges */ + mpc85xx_setup_hose(); +#endif + + /* setup the board related information for the enet controllers */ + pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); + pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; + pdata->interruptPHY = MPC85xx_IRQ_EXT5; + pdata->phyid = 0; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); + + pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2); + pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; + pdata->interruptPHY = MPC85xx_IRQ_EXT5; + pdata->phyid = 1; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_HDA1; +#endif +} + +static irqreturn_t cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs) +{ + while ((irq = cpm2_get_irq(regs)) >= 0) + __do_IRQ(irq, regs); + return IRQ_HANDLED; +} + +static struct irqaction cpm2_irqaction = { + .handler = cpm2_cascade, + .flags = SA_INTERRUPT, + .mask = CPU_MASK_NONE, + .name = "cpm2_cascade", +}; + +static void __init +mpc8560_ads_init_IRQ(void) +{ + /* Setup OpenPIC */ + mpc85xx_ads_init_IRQ(); + + /* Setup CPM2 PIC */ + cpm2_init_IRQ(); + + setup_irq(MPC85xx_IRQ_CPM, &cpm2_irqaction); + + return; +} + + + +/* ************************************************************************ */ +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + /* parse_bootinfo must always be called first */ + parse_bootinfo(find_bootinfo()); + + /* + * If we were passed in a board information, copy it into the + * residual data area. + */ + if (r3) { + memcpy((void *) __res, (void *) (r3 + KERNELBASE), + sizeof (bd_t)); + + } +#if defined(CONFIG_BLK_DEV_INITRD) + /* + * If the init RAM disk has been configured in, and there's a valid + * starting address for it, set it up. + */ + if (r4) { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif /* CONFIG_BLK_DEV_INITRD */ + + /* Copy the kernel command line arguments to a safe place. */ + + if (r6) { + *(char *) (r7 + KERNELBASE) = 0; + strcpy(cmd_line, (char *) (r6 + KERNELBASE)); + } + + identify_ppc_sys_by_id(mfspr(SPRN_SVR)); + + /* setup the PowerPC module struct */ + ppc_md.setup_arch = mpc8560ads_setup_arch; + ppc_md.show_cpuinfo = mpc85xx_ads_show_cpuinfo; + + ppc_md.init_IRQ = mpc8560_ads_init_IRQ; + ppc_md.get_irq = openpic_get_irq; + + ppc_md.restart = mpc85xx_restart; + ppc_md.power_off = mpc85xx_power_off; + ppc_md.halt = mpc85xx_halt; + + ppc_md.find_end_of_memory = mpc85xx_find_end_of_memory; + + ppc_md.time_init = NULL; + ppc_md.set_rtc_time = NULL; + ppc_md.get_rtc_time = NULL; + ppc_md.calibrate_decr = mpc85xx_calibrate_decr; + + if (ppc_md.progress) + ppc_md.progress("mpc8560ads_init(): exit", 0); + + return; +} diff --git a/arch/ppc/platforms/85xx/mpc8560_ads.h b/arch/ppc/platforms/85xx/mpc8560_ads.h new file mode 100644 index 00000000000..7df885d73e9 --- /dev/null +++ b/arch/ppc/platforms/85xx/mpc8560_ads.h @@ -0,0 +1,27 @@ +/* + * arch/ppc/platforms/mpc8560_ads.h + * + * MPC8540ADS board definitions + * + * Maintainer: Kumar Gala <kumar.gala@freescale.com> + * + * Copyright 2004 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __MACH_MPC8560ADS_H +#define __MACH_MPC8560ADS_H + +#include <linux/config.h> +#include <syslib/ppc85xx_setup.h> +#include <platforms/85xx/mpc85xx_ads_common.h> + +#define CPM_MAP_ADDR (CCSRBAR + MPC85xx_CPM_OFFSET) +#define PHY_INTERRUPT MPC85xx_IRQ_EXT7 + +#endif /* __MACH_MPC8560ADS_H */ diff --git a/arch/ppc/platforms/85xx/mpc85xx_ads_common.c b/arch/ppc/platforms/85xx/mpc85xx_ads_common.c new file mode 100644 index 00000000000..ba9f9f562c4 --- /dev/null +++ b/arch/ppc/platforms/85xx/mpc85xx_ads_common.c @@ -0,0 +1,225 @@ +/* + * arch/ppc/platforms/85xx/mpc85xx_ads_common.c + * + * MPC85xx ADS board common routines + * + * Maintainer: Kumar Gala <kumar.gala@freescale.com> + * + * Copyright 2004 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/major.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/seq_file.h> +#include <linux/serial.h> +#include <linux/module.h> + +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/atomic.h> +#include <asm/time.h> +#include <asm/io.h> +#include <asm/machdep.h> +#include <asm/prom.h> +#include <asm/open_pic.h> +#include <asm/bootinfo.h> +#include <asm/pci-bridge.h> +#include <asm/mpc85xx.h> +#include <asm/irq.h> +#include <asm/immap_85xx.h> +#include <asm/ppc_sys.h> + +#include <mm/mmu_decl.h> + +#include <platforms/85xx/mpc85xx_ads_common.h> + +#ifndef CONFIG_PCI +unsigned long isa_io_base = 0; +unsigned long isa_mem_base = 0; +#endif + +extern unsigned long total_memory; /* in mm/init */ + +unsigned char __res[sizeof (bd_t)]; + +/* Internal interrupts are all Level Sensitive, and Positive Polarity */ + +static u_char mpc85xx_ads_openpic_initsenses[] __initdata = { + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 0: L2 Cache */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 1: ECM */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 2: DDR DRAM */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 3: LBIU */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 4: DMA 0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 5: DMA 1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 6: DMA 2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 7: DMA 3 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 8: PCI/PCI-X */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 9: RIO Inbound Port Write Error */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 10: RIO Doorbell Inbound */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 11: RIO Outbound Message */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 12: RIO Inbound Message */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 13: TSEC 0 Transmit */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 14: TSEC 0 Receive */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 15: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 16: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 17: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 18: TSEC 0 Receive/Transmit Error */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 19: TSEC 1 Transmit */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 20: TSEC 1 Receive */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 21: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 22: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 23: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 24: TSEC 1 Receive/Transmit Error */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 25: Fast Ethernet */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 26: DUART */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 27: I2C */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 28: Performance Monitor */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 29: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 30: CPM */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 31: Unused */ + 0x0, /* External 0: */ +#if defined(CONFIG_PCI) + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 1: PCI slot 0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 2: PCI slot 1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 3: PCI slot 2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 4: PCI slot 3 */ +#else + 0x0, /* External 1: */ + 0x0, /* External 2: */ + 0x0, /* External 3: */ + 0x0, /* External 4: */ +#endif + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 5: PHY */ + 0x0, /* External 6: */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 7: PHY */ + 0x0, /* External 8: */ + 0x0, /* External 9: */ + 0x0, /* External 10: */ + 0x0, /* External 11: */ +}; + +/* ************************************************************************ */ +int +mpc85xx_ads_show_cpuinfo(struct seq_file *m) +{ + uint pvid, svid, phid1; + uint memsize = total_memory; + bd_t *binfo = (bd_t *) __res; + unsigned int freq; + + /* get the core frequency */ + freq = binfo->bi_intfreq; + + pvid = mfspr(SPRN_PVR); + svid = mfspr(SPRN_SVR); + + seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n"); + seq_printf(m, "Machine\t\t: mpc%sads\n", cur_ppc_sys_spec->ppc_sys_name); + seq_printf(m, "clock\t\t: %dMHz\n", freq / 1000000); + seq_printf(m, "PVR\t\t: 0x%x\n", pvid); + seq_printf(m, "SVR\t\t: 0x%x\n", svid); + + /* Display cpu Pll setting */ + phid1 = mfspr(SPRN_HID1); + seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); + + /* Display the amount of memory */ + seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); + + return 0; +} + +void __init +mpc85xx_ads_init_IRQ(void) +{ + bd_t *binfo = (bd_t *) __res; + /* Determine the Physical Address of the OpenPIC regs */ + phys_addr_t OpenPIC_PAddr = + binfo->bi_immr_base + MPC85xx_OPENPIC_OFFSET; + OpenPIC_Addr = ioremap(OpenPIC_PAddr, MPC85xx_OPENPIC_SIZE); + OpenPIC_InitSenses = mpc85xx_ads_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof (mpc85xx_ads_openpic_initsenses); + + /* Skip reserved space and internal sources */ + openpic_set_sources(0, 32, OpenPIC_Addr + 0x10200); + /* Map PIC IRQs 0-11 */ + openpic_set_sources(32, 12, OpenPIC_Addr + 0x10000); + + /* we let openpic interrupts starting from an offset, to + * leave space for cascading interrupts underneath. + */ + openpic_init(MPC85xx_OPENPIC_IRQ_OFFSET); + + return; +} + +#ifdef CONFIG_PCI +/* + * interrupt routing + */ + +int +mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * This is little evil, but works around the fact + * that revA boards have IDSEL starting at 18 + * and others boards (older) start at 12 + * + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {PIRQA, PIRQB, PIRQC, PIRQD}, /* IDSEL 2 */ + {PIRQD, PIRQA, PIRQB, PIRQC}, + {PIRQC, PIRQD, PIRQA, PIRQB}, + {PIRQB, PIRQC, PIRQD, PIRQA}, /* IDSEL 5 */ + {0, 0, 0, 0}, /* -- */ + {0, 0, 0, 0}, /* -- */ + {0, 0, 0, 0}, /* -- */ + {0, 0, 0, 0}, /* -- */ + {0, 0, 0, 0}, /* -- */ + {0, 0, 0, 0}, /* -- */ + {PIRQA, PIRQB, PIRQC, PIRQD}, /* IDSEL 12 */ + {PIRQD, PIRQA, PIRQB, PIRQC}, + {PIRQC, PIRQD, PIRQA, PIRQB}, + {PIRQB, PIRQC, PIRQD, PIRQA}, /* IDSEL 15 */ + {0, 0, 0, 0}, /* -- */ + {0, 0, 0, 0}, /* -- */ + {PIRQA, PIRQB, PIRQC, PIRQD}, /* IDSEL 18 */ + {PIRQD, PIRQA, PIRQB, PIRQC}, + {PIRQC, PIRQD, PIRQA, PIRQB}, + {PIRQB, PIRQC, PIRQD, PIRQA}, /* IDSEL 21 */ + }; + + const long min_idsel = 2, max_idsel = 21, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +} + +int +mpc85xx_exclude_device(u_char bus, u_char devfn) +{ + if (bus == 0 && PCI_SLOT(devfn) == 0) + return PCIBIOS_DEVICE_NOT_FOUND; + else + return PCIBIOS_SUCCESSFUL; +} + +#endif /* CONFIG_PCI */ diff --git a/arch/ppc/platforms/85xx/mpc85xx_ads_common.h b/arch/ppc/platforms/85xx/mpc85xx_ads_common.h new file mode 100644 index 00000000000..3875e839cff --- /dev/null +++ b/arch/ppc/platforms/85xx/mpc85xx_ads_common.h @@ -0,0 +1,50 @@ +/* + * arch/ppc/platforms/85xx/mpc85xx_ads_common.h + * + * MPC85XX ADS common board definitions + * + * Maintainer: Kumar Gala <kumar.gala@freescale.com> + * + * Copyright 2004 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __MACH_MPC85XX_ADS_H__ +#define __MACH_MPC85XX_ADS_H__ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/seq_file.h> +#include <asm/ppcboot.h> + +#define BOARD_CCSRBAR ((uint)0xe0000000) +#define BCSR_ADDR ((uint)0xf8000000) +#define BCSR_SIZE ((uint)(32 * 1024)) + +extern int mpc85xx_ads_show_cpuinfo(struct seq_file *m); +extern void mpc85xx_ads_init_IRQ(void) __init; +extern void mpc85xx_ads_map_io(void) __init; + +/* PCI interrupt controller */ +#define PIRQA MPC85xx_IRQ_EXT1 +#define PIRQB MPC85xx_IRQ_EXT2 +#define PIRQC MPC85xx_IRQ_EXT3 +#define PIRQD MPC85xx_IRQ_EXT4 + +#define MPC85XX_PCI1_LOWER_IO 0x00000000 +#define MPC85XX_PCI1_UPPER_IO 0x00ffffff + +#define MPC85XX_PCI1_LOWER_MEM 0x80000000 +#define MPC85XX_PCI1_UPPER_MEM 0x9fffffff + +#define MPC85XX_PCI1_IO_BASE 0xe2000000 +#define MPC85XX_PCI1_MEM_OFFSET 0x00000000 + +#define MPC85XX_PCI1_IO_SIZE 0x01000000 + +#endif /* __MACH_MPC85XX_ADS_H__ */ diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c new file mode 100644 index 00000000000..6c020d67ad7 --- /dev/null +++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c @@ -0,0 +1,467 @@ +/* + * arch/ppc/platform/85xx/mpc85xx_cds_common.c + * + * MPC85xx CDS board specific routines + * + * Maintainer: Kumar Gala <kumar.gala@freescale.com> + * + * Copyright 2004 Freescale Semiconductor, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/major.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/seq_file.h> +#include <linux/serial.h> +#include <linux/module.h> +#include <linux/root_dev.h> +#include <linux/initrd.h> +#include <linux/tty.h> +#include <linux/serial_core.h> +#include <linux/fsl_devices.h> + +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/atomic.h> +#include <asm/time.h> +#include <asm/todc.h> +#include <asm/io.h> +#include <asm/machdep.h> +#include <asm/prom.h> +#include <asm/open_pic.h> +#include <asm/bootinfo.h> +#include <asm/pci-bridge.h> +#include <asm/mpc85xx.h> +#include <asm/irq.h> +#include <asm/immap_85xx.h> +#include <asm/immap_cpm2.h> +#include <asm/ppc_sys.h> +#include <asm/kgdb.h> + +#include <mm/mmu_decl.h> +#include <syslib/cpm2_pic.h> +#include <syslib/ppc85xx_common.h> +#include <syslib/ppc85xx_setup.h> + + +#ifndef CONFIG_PCI +unsigned long isa_io_base = 0; +unsigned long isa_mem_base = 0; +#endif + +extern unsigned long total_memory; /* in mm/init */ + +unsigned char __res[sizeof (bd_t)]; + +static int cds_pci_slot = 2; +static volatile u8 * cadmus; + +/* Internal interrupts are all Level Sensitive, and Positive Polarity */ + +static u_char mpc85xx_cds_openpic_initsenses[] __initdata = { + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 0: L2 Cache */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 1: ECM */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 2: DDR DRAM */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 3: LBIU */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 4: DMA 0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 5: DMA 1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 6: DMA 2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 7: DMA 3 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 8: PCI/PCI-X */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 9: RIO Inbound Port Write Error */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 10: RIO Doorbell Inbound */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 11: RIO Outbound Message */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 12: RIO Inbound Message */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 13: TSEC 0 Transmit */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 14: TSEC 0 Receive */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 15: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 16: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 17: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 18: TSEC 0 Receive/Transmit Error */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 19: TSEC 1 Transmit */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 20: TSEC 1 Receive */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 21: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 22: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 23: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 24: TSEC 1 Receive/Transmit Error */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 25: Fast Ethernet */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 26: DUART */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 27: I2C */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 28: Performance Monitor */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 29: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 30: CPM */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 31: Unused */ +#if defined(CONFIG_PCI) + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 0: PCI1 slot */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 1: PCI1 slot */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 2: PCI1 slot */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 3: PCI1 slot */ +#else + 0x0, /* External 0: */ + 0x0, /* External 1: */ + 0x0, /* External 2: */ + 0x0, /* External 3: */ +#endif + 0x0, /* External 4: */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 5: PHY */ + 0x0, /* External 6: */ + 0x0, /* External 7: */ + 0x0, /* External 8: */ + 0x0, /* External 9: */ + 0x0, /* External 10: */ +#if defined(CONFIG_85xx_PCI2) && defined(CONFIG_PCI) + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 11: PCI2 slot 0 */ +#else + 0x0, /* External 11: */ +#endif +}; + +/* ************************************************************************ */ +int +mpc85xx_cds_show_cpuinfo(struct seq_file *m) +{ + uint pvid, svid, phid1; + uint memsize = total_memory; + bd_t *binfo = (bd_t *) __res; + unsigned int freq; + + /* get the core frequency */ + freq = binfo->bi_intfreq; + + pvid = mfspr(SPRN_PVR); + svid = mfspr(SPRN_SVR); + + seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n"); + seq_printf(m, "Machine\t\t: CDS - MPC%s (%x)\n", cur_ppc_sys_spec->ppc_sys_name, cadmus[CM_VER]); + seq_printf(m, "clock\t\t: %dMHz\n", freq / 1000000); + seq_printf(m, "PVR\t\t: 0x%x\n", pvid); + seq_printf(m, "SVR\t\t: 0x%x\n", svid); + + /* Display cpu Pll setting */ + phid1 = mfspr(SPRN_HID1); + seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); + + /* Display the amount of memory */ + seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); + + return 0; +} + +#ifdef CONFIG_CPM2 +static void cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs) +{ + while((irq = cpm2_get_irq(regs)) >= 0) + __do_IRQ(irq, regs); +} + +static struct irqaction cpm2_irqaction = { + .handler = cpm2_cascade, + .flags = SA_INTERRUPT, + .mask = CPU_MASK_NONE, + .name = "cpm2_cascade", +}; +#endif /* CONFIG_CPM2 */ + +void __init +mpc85xx_cds_init_IRQ(void) +{ + bd_t *binfo = (bd_t *) __res; + + /* Determine the Physical Address of the OpenPIC regs */ + phys_addr_t OpenPIC_PAddr = binfo->bi_immr_base + MPC85xx_OPENPIC_OFFSET; + OpenPIC_Addr = ioremap(OpenPIC_PAddr, MPC85xx_OPENPIC_SIZE); + OpenPIC_InitSenses = mpc85xx_cds_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof (mpc85xx_cds_openpic_initsenses); + + /* Skip reserved space and internal sources */ + openpic_set_sources(0, 32, OpenPIC_Addr + 0x10200); + /* Map PIC IRQs 0-11 */ + openpic_set_sources(32, 12, OpenPIC_Addr + 0x10000); + + /* we let openpic interrupts starting from an offset, to + * leave space for cascading interrupts underneath. + */ + openpic_init(MPC85xx_OPENPIC_IRQ_OFFSET); + +#ifdef CONFIG_CPM2 + /* Setup CPM2 PIC */ + cpm2_init_IRQ(); + + setup_irq(MPC85xx_IRQ_CPM, &cpm2_irqaction); +#endif + + return; +} + +#ifdef CONFIG_PCI +/* + * interrupt routing + */ +int +mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); + + if (!hose->index) + { + /* Handle PCI1 interrupts */ + char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + + /* Note IRQ assignment for slots is based on which slot the elysium is + * in -- in this setup elysium is in slot #2 (this PIRQA as first + * interrupt on slot */ + { + { 0, 1, 2, 3 }, /* 16 - PMC */ + { 3, 0, 0, 0 }, /* 17 P2P (Tsi320) */ + { 0, 1, 2, 3 }, /* 18 - Slot 1 */ + { 1, 2, 3, 0 }, /* 19 - Slot 2 */ + { 2, 3, 0, 1 }, /* 20 - Slot 3 */ + { 3, 0, 1, 2 }, /* 21 - Slot 4 */ + }; + + const long min_idsel = 16, max_idsel = 21, irqs_per_slot = 4; + int i, j; + + for (i = 0; i < 6; i++) + for (j = 0; j < 4; j++) + pci_irq_table[i][j] = + ((pci_irq_table[i][j] + 5 - + cds_pci_slot) & 0x3) + PIRQ0A; + + return PCI_IRQ_TABLE_LOOKUP; + } else { + /* Handle PCI2 interrupts (if we have one) */ + char pci_irq_table[][4] = + { + /* + * We only have one slot and one interrupt + * going to PIRQA - PIRQD */ + { PIRQ1A, PIRQ1A, PIRQ1A, PIRQ1A }, /* 21 - slot 0 */ + }; + + const long min_idsel = 21, max_idsel = 21, irqs_per_slot = 4; + + return PCI_IRQ_TABLE_LOOKUP; + } +} + +#define ARCADIA_HOST_BRIDGE_IDSEL 17 +#define ARCADIA_2ND_BRIDGE_IDSEL 3 + +extern int mpc85xx_pci1_last_busno; + +int +mpc85xx_exclude_device(u_char bus, u_char devfn) +{ + if (bus == 0 && PCI_SLOT(devfn) == 0) + return PCIBIOS_DEVICE_NOT_FOUND; +#ifdef CONFIG_85xx_PCI2 + if (mpc85xx_pci1_last_busno) + if (bus == (mpc85xx_pci1_last_busno + 1) && PCI_SLOT(devfn) == 0) + return PCIBIOS_DEVICE_NOT_FOUND; +#endif + /* We explicitly do not go past the Tundra 320 Bridge */ + if (bus == 1) + return PCIBIOS_DEVICE_NOT_FOUND; + if ((bus == 0) && (PCI_SLOT(devfn) == ARCADIA_2ND_BRIDGE_IDSEL)) + return PCIBIOS_DEVICE_NOT_FOUND; + else + return PCIBIOS_SUCCESSFUL; +} +#endif /* CONFIG_PCI */ + +TODC_ALLOC(); + +/* ************************************************************************ + * + * Setup the architecture + * + */ +static void __init +mpc85xx_cds_setup_arch(void) +{ + bd_t *binfo = (bd_t *) __res; + unsigned int freq; + struct gianfar_platform_data *pdata; + + /* get the core frequency */ + freq = binfo->bi_intfreq; + + printk("mpc85xx_cds_setup_arch\n"); + +#ifdef CONFIG_CPM2 + cpm2_reset(); +#endif + + cadmus = ioremap(CADMUS_BASE, CADMUS_SIZE); + cds_pci_slot = ((cadmus[CM_CSR] >> 6) & 0x3) + 1; + printk("CDS Version = %x in PCI slot %d\n", cadmus[CM_VER], cds_pci_slot); + + /* Setup TODC access */ + TODC_INIT(TODC_TYPE_DS1743, + 0, + 0, + ioremap(CDS_RTC_ADDR, CDS_RTC_SIZE), + 8); + + /* Set loops_per_jiffy to a half-way reasonable value, + for use until calibrate_delay gets called. */ + loops_per_jiffy = freq / HZ; + +#ifdef CONFIG_PCI + /* setup PCI host bridges */ + mpc85xx_setup_hose(); +#endif + +#ifdef CONFIG_SERIAL_8250 + mpc85xx_early_serial_map(); +#endif + +#ifdef CONFIG_SERIAL_TEXT_DEBUG + /* Invalidate the entry we stole earlier the serial ports + * should be properly mapped */ + invalidate_tlbcam_entry(NUM_TLBCAMS - 1); +#endif + + /* setup the board related information for the enet controllers */ + pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); + pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; + pdata->interruptPHY = MPC85xx_IRQ_EXT5; + pdata->phyid = 0; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); + + pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2); + pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; + pdata->interruptPHY = MPC85xx_IRQ_EXT5; + pdata->phyid = 1; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); + + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_HDA1; +#endif +} + +/* ************************************************************************ */ +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + /* parse_bootinfo must always be called first */ + parse_bootinfo(find_bootinfo()); + + /* + * If we were passed in a board information, copy it into the + * residual data area. + */ + if (r3) { + memcpy((void *) __res, (void *) (r3 + KERNELBASE), + sizeof (bd_t)); + + } +#ifdef CONFIG_SERIAL_TEXT_DEBUG + { + bd_t *binfo = (bd_t *) __res; + struct uart_port p; + + /* Use the last TLB entry to map CCSRBAR to allow access to DUART regs */ + settlbcam(NUM_TLBCAMS - 1, binfo->bi_immr_base, + binfo->bi_immr_base, MPC85xx_CCSRBAR_SIZE, _PAGE_IO, 0); + + memset(&p, 0, sizeof (p)); + p.iotype = SERIAL_IO_MEM; + p.membase = (void *) binfo->bi_immr_base + MPC85xx_UART0_OFFSET; + p.uartclk = binfo->bi_busfreq; + + gen550_init(0, &p); + + memset(&p, 0, sizeof (p)); + p.iotype = SERIAL_IO_MEM; + p.membase = (void *) binfo->bi_immr_base + MPC85xx_UART1_OFFSET; + p.uartclk = binfo->bi_busfreq; + + gen550_init(1, &p); + } +#endif + +#if defined(CONFIG_BLK_DEV_INITRD) + /* + * If the init RAM disk has been configured in, and there's a valid + * starting address for it, set it up. + */ + if (r4) { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif /* CONFIG_BLK_DEV_INITRD */ + + /* Copy the kernel command line arguments to a safe place. */ + + if (r6) { + *(char *) (r7 + KERNELBASE) = 0; + strcpy(cmd_line, (char *) (r6 + KERNELBASE)); + } + + identify_ppc_sys_by_id(mfspr(SPRN_SVR)); + + /* setup the PowerPC module struct */ + ppc_md.setup_arch = mpc85xx_cds_setup_arch; + ppc_md.show_cpuinfo = mpc85xx_cds_show_cpuinfo; + + ppc_md.init_IRQ = mpc85xx_cds_init_IRQ; + ppc_md.get_irq = openpic_get_irq; + + ppc_md.restart = mpc85xx_restart; + ppc_md.power_off = mpc85xx_power_off; + ppc_md.halt = mpc85xx_halt; + + ppc_md.find_end_of_memory = mpc85xx_find_end_of_memory; + + ppc_md.calibrate_decr = mpc85xx_calibrate_decr; + + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; + +#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG) + ppc_md.progress = gen550_progress; +#endif /* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */ + + if (ppc_md.progress) + ppc_md.progress("mpc85xx_cds_init(): exit", 0); + + return; +} diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.h b/arch/ppc/platforms/85xx/mpc85xx_cds_common.h new file mode 100644 index 00000000000..7627d77504b --- /dev/null +++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.h @@ -0,0 +1,80 @@ +/* + * arch/ppc/platforms/85xx/mpc85xx_cds_common.h + * + * MPC85xx CDS board definitions + * + * Maintainer: Kumar Gala <kumar.gala@freescale.com> + * + * Copyright 2004 Freescale Semiconductor, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __MACH_MPC85XX_CDS_H__ +#define __MACH_MPC85XX_CDS_H__ + +#include <linux/config.h> +#include <linux/serial.h> +#include <asm/ppcboot.h> +#include <linux/initrd.h> +#include <syslib/ppc85xx_setup.h> + +#define BOARD_CCSRBAR ((uint)0xe0000000) +#define CCSRBAR_SIZE ((uint)1024*1024) + +/* CADMUS info */ +#define CADMUS_BASE (0xf8004000) +#define CADMUS_SIZE (256) +#define CM_VER (0) +#define CM_CSR (1) +#define CM_RST (2) + +/* CDS NVRAM/RTC */ +#define CDS_RTC_ADDR (0xf8000000) +#define CDS_RTC_SIZE (8 * 1024) + +/* PCI config */ +#define PCI1_CFG_ADDR_OFFSET (0x8000) +#define PCI1_CFG_DATA_OFFSET (0x8004) + +#define PCI2_CFG_ADDR_OFFSET (0x9000) +#define PCI2_CFG_DATA_OFFSET (0x9004) + +/* PCI interrupt controller */ +#define PIRQ0A MPC85xx_IRQ_EXT0 +#define PIRQ0B MPC85xx_IRQ_EXT1 +#define PIRQ0C MPC85xx_IRQ_EXT2 +#define PIRQ0D MPC85xx_IRQ_EXT3 +#define PIRQ1A MPC85xx_IRQ_EXT11 + +/* PCI 1 memory map */ +#define MPC85XX_PCI1_LOWER_IO 0x00000000 +#define MPC85XX_PCI1_UPPER_IO 0x00ffffff + +#define MPC85XX_PCI1_LOWER_MEM 0x80000000 +#define MPC85XX_PCI1_UPPER_MEM 0x9fffffff + +#define MPC85XX_PCI1_IO_BASE 0xe2000000 +#define MPC85XX_PCI1_MEM_OFFSET 0x00000000 + +#define MPC85XX_PCI1_IO_SIZE 0x01000000 + +/* PCI 2 memory map */ +/* Note: the standard PPC fixups will cause IO space to get bumped by + * hose->io_base_virt - isa_io_base => MPC85XX_PCI1_IO_SIZE */ +#define MPC85XX_PCI2_LOWER_IO 0x00000000 +#define MPC85XX_PCI2_UPPER_IO 0x00ffffff + +#define MPC85XX_PCI2_LOWER_MEM 0xa0000000 +#define MPC85XX_PCI2_UPPER_MEM 0xbfffffff + +#define MPC85XX_PCI2_IO_BASE 0xe3000000 +#define MPC85XX_PCI2_MEM_OFFSET 0x00000000 + +#define MPC85XX_PCI2_IO_SIZE 0x01000000 + +#endif /* __MACH_MPC85XX_CDS_H__ */ diff --git a/arch/ppc/platforms/85xx/sbc8560.c b/arch/ppc/platforms/85xx/sbc8560.c new file mode 100644 index 00000000000..9ab05e590c3 --- /dev/null +++ b/arch/ppc/platforms/85xx/sbc8560.c @@ -0,0 +1,227 @@ +/* + * arch/ppc/platforms/85xx/sbc8560.c + * + * Wind River SBC8560 board specific routines + * + * Maintainer: Kumar Gala <kumar.gala@freescale.com> + * + * Copyright 2004 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/major.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/seq_file.h> +#include <linux/root_dev.h> +#include <linux/serial.h> +#include <linux/tty.h> /* for linux/serial_core.h */ +#include <linux/serial_core.h> +#include <linux/initrd.h> +#include <linux/module.h> +#include <linux/fsl_devices.h> + +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/atomic.h> +#include <asm/time.h> +#include <asm/io.h> +#include <asm/machdep.h> +#include <asm/prom.h> +#include <asm/open_pic.h> +#include <asm/bootinfo.h> +#include <asm/pci-bridge.h> +#include <asm/mpc85xx.h> +#include <asm/irq.h> +#include <asm/immap_85xx.h> +#include <asm/kgdb.h> +#include <asm/ppc_sys.h> +#include <mm/mmu_decl.h> + +#include <syslib/ppc85xx_common.h> +#include <syslib/ppc85xx_setup.h> + +#ifdef CONFIG_SERIAL_8250 +static void __init +sbc8560_early_serial_map(void) +{ + struct uart_port uart_req; + + /* Setup serial port access */ + memset(&uart_req, 0, sizeof (uart_req)); + uart_req.irq = MPC85xx_IRQ_EXT9; + uart_req.flags = STD_COM_FLAGS; + uart_req.uartclk = BASE_BAUD * 16; + uart_req.iotype = SERIAL_IO_MEM; + uart_req.mapbase = UARTA_ADDR; + uart_req.membase = ioremap(uart_req.mapbase, MPC85xx_UART0_SIZE); + uart_req.type = PORT_16650; + +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) + gen550_init(0, &uart_req); +#endif + + if (early_serial_setup(&uart_req) != 0) + printk("Early serial init of port 0 failed\n"); + + /* Assume early_serial_setup() doesn't modify uart_req */ + uart_req.line = 1; + uart_req.mapbase = UARTB_ADDR; + uart_req.membase = ioremap(uart_req.mapbase, MPC85xx_UART1_SIZE); + uart_req.irq = MPC85xx_IRQ_EXT10; + +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) + gen550_init(1, &uart_req); +#endif + + if (early_serial_setup(&uart_req) != 0) + printk("Early serial init of port 1 failed\n"); +} +#endif + +/* ************************************************************************ + * + * Setup the architecture + * + */ +static void __init +sbc8560_setup_arch(void) +{ + bd_t *binfo = (bd_t *) __res; + unsigned int freq; + struct gianfar_platform_data *pdata; + + /* get the core frequency */ + freq = binfo->bi_intfreq; + + if (ppc_md.progress) + ppc_md.progress("sbc8560_setup_arch()", 0); + + /* Set loops_per_jiffy to a half-way reasonable value, + for use until calibrate_delay gets called. */ + loops_per_jiffy = freq / HZ; + +#ifdef CONFIG_PCI + /* setup PCI host bridges */ + mpc85xx_setup_hose(); +#endif +#ifdef CONFIG_SERIAL_8250 + sbc8560_early_serial_map(); +#endif +#ifdef CONFIG_SERIAL_TEXT_DEBUG + /* Invalidate the entry we stole earlier the serial ports + * should be properly mapped */ + invalidate_tlbcam_entry(NUM_TLBCAMS - 1); +#endif + + /* setup the board related information for the enet controllers */ + pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); + pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; + pdata->interruptPHY = MPC85xx_IRQ_EXT6; + pdata->phyid = 25; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); + + pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2); + pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; + pdata->interruptPHY = MPC85xx_IRQ_EXT7; + pdata->phyid = 26; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_HDA1; +#endif +} + +/* ************************************************************************ */ +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + /* parse_bootinfo must always be called first */ + parse_bootinfo(find_bootinfo()); + + /* + * If we were passed in a board information, copy it into the + * residual data area. + */ + if (r3) { + memcpy((void *) __res, (void *) (r3 + KERNELBASE), + sizeof (bd_t)); + } + +#ifdef CONFIG_SERIAL_TEXT_DEBUG + /* Use the last TLB entry to map CCSRBAR to allow access to DUART regs */ + settlbcam(NUM_TLBCAMS - 1, UARTA_ADDR, + UARTA_ADDR, 0x1000, _PAGE_IO, 0); +#endif + +#if defined(CONFIG_BLK_DEV_INITRD) + /* + * If the init RAM disk has been configured in, and there's a valid + * starting address for it, set it up. + */ + if (r4) { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif /* CONFIG_BLK_DEV_INITRD */ + + /* Copy the kernel command line arguments to a safe place. */ + + if (r6) { + *(char *) (r7 + KERNELBASE) = 0; + strcpy(cmd_line, (char *) (r6 + KERNELBASE)); + } + + identify_ppc_sys_by_id(mfspr(SPRN_SVR)); + + /* setup the PowerPC module struct */ + ppc_md.setup_arch = sbc8560_setup_arch; + ppc_md.show_cpuinfo = sbc8560_show_cpuinfo; + + ppc_md.init_IRQ = sbc8560_init_IRQ; + ppc_md.get_irq = openpic_get_irq; + + ppc_md.restart = mpc85xx_restart; + ppc_md.power_off = mpc85xx_power_off; + ppc_md.halt = mpc85xx_halt; + + ppc_md.find_end_of_memory = mpc85xx_find_end_of_memory; + + ppc_md.time_init = NULL; + ppc_md.set_rtc_time = NULL; + ppc_md.get_rtc_time = NULL; + ppc_md.calibrate_decr = mpc85xx_calibrate_decr; + +#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG) + ppc_md.progress = gen550_progress; +#endif /* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */ + + if (ppc_md.progress) + ppc_md.progress("sbc8560_init(): exit", 0); +} diff --git a/arch/ppc/platforms/85xx/sbc8560.h b/arch/ppc/platforms/85xx/sbc8560.h new file mode 100644 index 00000000000..5e1b00c77da --- /dev/null +++ b/arch/ppc/platforms/85xx/sbc8560.h @@ -0,0 +1,49 @@ +/* + * arch/ppc/platforms/85xx/sbc8560.h + * + * Wind River SBC8560 board definitions + * + * Copyright 2003 Motorola Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __MACH_SBC8560_H__ +#define __MACH_SBC8560_H__ + +#include <linux/config.h> +#include <platforms/85xx/sbc85xx.h> + +#define CPM_MAP_ADDR (CCSRBAR + MPC85xx_CPM_OFFSET) + +#ifdef CONFIG_SERIAL_MANY_PORTS +#define RS_TABLE_SIZE 64 +#else +#define RS_TABLE_SIZE 2 +#endif + +/* Rate for the 1.8432 Mhz clock for the onboard serial chip */ +#define BASE_BAUD ( 1843200 / 16 ) + +#ifdef CONFIG_SERIAL_DETECT_IRQ +#define STD_COM_FLAGS (ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ) +#else +#define STD_COM_FLAGS (ASYNC_SKIP_TEST) +#endif + +#define STD_SERIAL_PORT_DFNS \ + { 0, BASE_BAUD, UARTA_ADDR, MPC85xx_IRQ_EXT9, STD_COM_FLAGS, /* ttyS0 */ \ + iomem_base: (u8 *)UARTA_ADDR, \ + io_type: SERIAL_IO_MEM }, \ + { 0, BASE_BAUD, UARTB_ADDR, MPC85xx_IRQ_EXT10, STD_COM_FLAGS, /* ttyS1 */ \ + iomem_base: (u8 *)UARTB_ADDR, \ + io_type: SERIAL_IO_MEM }, + +#define SERIAL_PORT_DFNS \ + STD_SERIAL_PORT_DFNS + +#endif /* __MACH_SBC8560_H__ */ diff --git a/arch/ppc/platforms/85xx/sbc85xx.c b/arch/ppc/platforms/85xx/sbc85xx.c new file mode 100644 index 00000000000..2d638c1c1bd --- /dev/null +++ b/arch/ppc/platforms/85xx/sbc85xx.c @@ -0,0 +1,203 @@ +/* + * arch/ppc/platform/85xx/sbc85xx.c + * + * WindRiver PowerQUICC III SBC85xx board common routines + * + * Copyright 2002, 2003 Motorola Inc. + * Copyright 2004 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/major.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/seq_file.h> +#include <linux/serial.h> +#include <linux/module.h> + +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/atomic.h> +#include <asm/time.h> +#include <asm/io.h> +#include <asm/machdep.h> +#include <asm/prom.h> +#include <asm/open_pic.h> +#include <asm/bootinfo.h> +#include <asm/pci-bridge.h> +#include <asm/mpc85xx.h> +#include <asm/irq.h> +#include <asm/immap_85xx.h> +#include <asm/ppc_sys.h> + +#include <mm/mmu_decl.h> + +#include <platforms/85xx/sbc85xx.h> + +unsigned char __res[sizeof (bd_t)]; + +#ifndef CONFIG_PCI +unsigned long isa_io_base = 0; +unsigned long isa_mem_base = 0; +unsigned long pci_dram_offset = 0; +#endif + +extern unsigned long total_memory; /* in mm/init */ + +/* Internal interrupts are all Level Sensitive, and Positive Polarity */ + +static u_char sbc8560_openpic_initsenses[] __initdata = { + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 0: L2 Cache */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 1: ECM */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 2: DDR DRAM */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 3: LBIU */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 4: DMA 0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 5: DMA 1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 6: DMA 2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 7: DMA 3 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 8: PCI/PCI-X */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 9: RIO Inbound Port Write Error */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 10: RIO Doorbell Inbound */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 11: RIO Outbound Message */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 12: RIO Inbound Message */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 13: TSEC 0 Transmit */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 14: TSEC 0 Receive */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 15: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 16: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 17: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 18: TSEC 0 Receive/Transmit Error */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 19: TSEC 1 Transmit */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 20: TSEC 1 Receive */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 21: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 22: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 23: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 24: TSEC 1 Receive/Transmit Error */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 25: Fast Ethernet */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 26: DUART */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 27: I2C */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 28: Performance Monitor */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 29: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 30: CPM */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 31: Unused */ + 0x0, /* External 0: */ + 0x0, /* External 1: */ +#if defined(CONFIG_PCI) + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 2: PCI slot 0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 3: PCI slot 1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 4: PCI slot 2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 5: PCI slot 3 */ +#else + 0x0, /* External 2: */ + 0x0, /* External 3: */ + 0x0, /* External 4: */ + 0x0, /* External 5: */ +#endif + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 6: PHY */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 7: PHY */ + 0x0, /* External 8: */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* External 9: PHY */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* External 10: PHY */ + 0x0, /* External 11: */ +}; + +/* ************************************************************************ */ +int +sbc8560_show_cpuinfo(struct seq_file *m) +{ + uint pvid, svid, phid1; + uint memsize = total_memory; + bd_t *binfo = (bd_t *) __res; + unsigned int freq; + + /* get the core frequency */ + freq = binfo->bi_intfreq; + + pvid = mfspr(SPRN_PVR); + svid = mfspr(SPRN_SVR); + + seq_printf(m, "Vendor\t\t: Wind River\n"); + seq_printf(m, "Machine\t\t: SBC%s\n", cur_ppc_sys_spec->ppc_sys_name); + seq_printf(m, "clock\t\t: %dMHz\n", freq / 1000000); + seq_printf(m, "PVR\t\t: 0x%x\n", pvid); + seq_printf(m, "SVR\t\t: 0x%x\n", svid); + + /* Display cpu Pll setting */ + phid1 = mfspr(SPRN_HID1); + seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); + + /* Display the amount of memory */ + seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); + + return 0; +} + +void __init +sbc8560_init_IRQ(void) +{ + bd_t *binfo = (bd_t *) __res; + /* Determine the Physical Address of the OpenPIC regs */ + phys_addr_t OpenPIC_PAddr = + binfo->bi_immr_base + MPC85xx_OPENPIC_OFFSET; + OpenPIC_Addr = ioremap(OpenPIC_PAddr, MPC85xx_OPENPIC_SIZE); + OpenPIC_InitSenses = sbc8560_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof (sbc8560_openpic_initsenses); + + /* Skip reserved space and internal sources */ + openpic_set_sources(0, 32, OpenPIC_Addr + 0x10200); + /* Map PIC IRQs 0-11 */ + openpic_set_sources(32, 12, OpenPIC_Addr + 0x10000); + + /* we let openpic interrupts starting from an offset, to + * leave space for cascading interrupts underneath. + */ + openpic_init(MPC85xx_OPENPIC_IRQ_OFFSET); + + return; +} + +/* + * interrupt routing + */ + +#ifdef CONFIG_PCI +int mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel, + unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {PIRQA, PIRQB, PIRQC, PIRQD}, + {PIRQD, PIRQA, PIRQB, PIRQC}, + {PIRQC, PIRQD, PIRQA, PIRQB}, + {PIRQB, PIRQC, PIRQD, PIRQA}, + }; + + const long min_idsel = 12, max_idsel = 15, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +} + +int mpc85xx_exclude_device(u_char bus, u_char devfn) +{ + if (bus == 0 && PCI_SLOT(devfn) == 0) + return PCIBIOS_DEVICE_NOT_FOUND; + else + return PCIBIOS_SUCCESSFUL; +} +#endif /* CONFIG_PCI */ diff --git a/arch/ppc/platforms/85xx/sbc85xx.h b/arch/ppc/platforms/85xx/sbc85xx.h new file mode 100644 index 00000000000..7af93c691a6 --- /dev/null +++ b/arch/ppc/platforms/85xx/sbc85xx.h @@ -0,0 +1,55 @@ +/* + * arch/ppc/platforms/85xx/sbc85xx.h + * + * WindRiver PowerQUICC III SBC85xx common board definitions + * + * Copyright 2003 Motorola Inc. + * Copyright 2004 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __PLATFORMS_85XX_SBC85XX_H__ +#define __PLATFORMS_85XX_SBC85XX_H__ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/seq_file.h> +#include <asm/ppcboot.h> + +#define BOARD_CCSRBAR ((uint)0xff700000) +#define CCSRBAR_SIZE ((uint)1024*1024) + +#define BCSR_ADDR ((uint)0xfc000000) +#define BCSR_SIZE ((uint)(16 * 1024 * 1024)) + +#define UARTA_ADDR (BCSR_ADDR + 0x00700000) +#define UARTB_ADDR (BCSR_ADDR + 0x00800000) +#define RTC_DEVICE_ADDR (BCSR_ADDR + 0x00900000) +#define EEPROM_ADDR (BCSR_ADDR + 0x00b00000) + +extern int sbc8560_show_cpuinfo(struct seq_file *m); +extern void sbc8560_init_IRQ(void) __init; + +/* PCI interrupt controller */ +#define PIRQA MPC85xx_IRQ_EXT1 +#define PIRQB MPC85xx_IRQ_EXT2 +#define PIRQC MPC85xx_IRQ_EXT3 +#define PIRQD MPC85xx_IRQ_EXT4 + +#define MPC85XX_PCI1_LOWER_IO 0x00000000 +#define MPC85XX_PCI1_UPPER_IO 0x00ffffff + +#define MPC85XX_PCI1_LOWER_MEM 0x80000000 +#define MPC85XX_PCI1_UPPER_MEM 0x9fffffff + +#define MPC85XX_PCI1_IO_BASE 0xe2000000 +#define MPC85XX_PCI1_MEM_OFFSET 0x00000000 + +#define MPC85XX_PCI1_IO_SIZE 0x01000000 + +#endif /* __PLATFORMS_85XX_SBC85XX_H__ */ diff --git a/arch/ppc/platforms/85xx/stx_gp3.c b/arch/ppc/platforms/85xx/stx_gp3.c new file mode 100644 index 00000000000..bc95836e417 --- /dev/null +++ b/arch/ppc/platforms/85xx/stx_gp3.c @@ -0,0 +1,355 @@ +/* + * arch/ppc/platforms/85xx/stx_gp3.c + * + * STx GP3 board specific routines + * + * Dan Malek <dan@embeddededge.com> + * Copyright 2004 Embedded Edge, LLC + * + * Copied from mpc8560_ads.c + * Copyright 2002, 2003 Motorola Inc. + * + * Ported to 2.6, Matt Porter <mporter@kernel.crashing.org> + * Copyright 2004-2005 MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/major.h> +#include <linux/blkdev.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/root_dev.h> +#include <linux/seq_file.h> +#include <linux/serial.h> +#include <linux/initrd.h> +#include <linux/module.h> +#include <linux/fsl_devices.h> +#include <linux/interrupt.h> + +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/atomic.h> +#include <asm/time.h> +#include <asm/io.h> +#include <asm/machdep.h> +#include <asm/prom.h> +#include <asm/open_pic.h> +#include <asm/bootinfo.h> +#include <asm/pci-bridge.h> +#include <asm/mpc85xx.h> +#include <asm/irq.h> +#include <asm/immap_85xx.h> +#include <asm/immap_cpm2.h> +#include <asm/mpc85xx.h> +#include <asm/ppc_sys.h> + +#include <syslib/cpm2_pic.h> +#include <syslib/ppc85xx_common.h> + +extern void cpm2_reset(void); + +unsigned char __res[sizeof(bd_t)]; + +#ifndef CONFIG_PCI +unsigned long isa_io_base = 0; +unsigned long isa_mem_base = 0; +unsigned long pci_dram_offset = 0; +#endif + +/* Internal interrupts are all Level Sensitive, and Positive Polarity */ +static u8 gp3_openpic_initsenses[] __initdata = { + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 0: L2 Cache */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 1: ECM */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 2: DDR DRAM */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 3: LBIU */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 4: DMA 0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 5: DMA 1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 6: DMA 2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 7: DMA 3 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 8: PCI/PCI-X */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 9: RIO Inbound Port Write Error */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 10: RIO Doorbell Inbound */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 11: RIO Outbound Message */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 12: RIO Inbound Message */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 13: TSEC 0 Transmit */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 14: TSEC 0 Receive */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 15: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 16: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 17: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 18: TSEC 0 Receive/Transmit Error */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 19: TSEC 1 Transmit */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 20: TSEC 1 Receive */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 21: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 22: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 23: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 24: TSEC 1 Receive/Transmit Error */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 25: Fast Ethernet */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 26: DUART */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 27: I2C */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 28: Performance Monitor */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 29: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 30: CPM */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 31: Unused */ + 0x0, /* External 0: */ +#if defined(CONFIG_PCI) + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 1: PCI slot 0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 2: PCI slot 1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 3: PCI slot 2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 4: PCI slot 3 */ +#else + 0x0, /* External 1: */ + 0x0, /* External 2: */ + 0x0, /* External 3: */ + 0x0, /* External 4: */ +#endif + 0x0, /* External 5: */ + 0x0, /* External 6: */ + 0x0, /* External 7: */ + 0x0, /* External 8: */ + 0x0, /* External 9: */ + 0x0, /* External 10: */ + 0x0, /* External 11: */ +}; + +/* + * Setup the architecture + */ +static void __init +gp3_setup_arch(void) +{ + bd_t *binfo = (bd_t *) __res; + unsigned int freq; + struct gianfar_platform_data *pdata; + + cpm2_reset(); + + /* get the core frequency */ + freq = binfo->bi_intfreq; + + if (ppc_md.progress) + ppc_md.progress("gp3_setup_arch()", 0); + + /* Set loops_per_jiffy to a half-way reasonable value, + for use until calibrate_delay gets called. */ + loops_per_jiffy = freq / HZ; + +#ifdef CONFIG_PCI + /* setup PCI host bridges */ + mpc85xx_setup_hose(); +#endif + + /* setup the board related information for the enet controllers */ + pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); +/* pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; */ + pdata->interruptPHY = MPC85xx_IRQ_EXT5; + pdata->phyid = 2; + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); + + pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2); +/* pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; */ + pdata->interruptPHY = MPC85xx_IRQ_EXT5; + pdata->phyid = 4; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_HDA1; +#endif + + printk ("bi_immr_base = %8.8lx\n", binfo->bi_immr_base); +} + +static irqreturn_t cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs) +{ + while ((irq = cpm2_get_irq(regs)) >= 0) + __do_IRQ(irq, regs); + + return IRQ_HANDLED; +} + +static struct irqaction cpm2_irqaction = { + .handler = cpm2_cascade, + .flags = SA_INTERRUPT, + .mask = CPU_MASK_NONE, + .name = "cpm2_cascade", +}; + +static void __init +gp3_init_IRQ(void) +{ + int i; + bd_t *binfo = (bd_t *) __res; + + /* + * Setup OpenPIC + */ + + /* Determine the Physical Address of the OpenPIC regs */ + phys_addr_t OpenPIC_PAddr = + binfo->bi_immr_base + MPC85xx_OPENPIC_OFFSET; + OpenPIC_Addr = ioremap(OpenPIC_PAddr, MPC85xx_OPENPIC_SIZE); + OpenPIC_InitSenses = gp3_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof (gp3_openpic_initsenses); + + /* Skip reserved space and internal sources */ + openpic_set_sources(0, 32, OpenPIC_Addr + 0x10200); + + /* Map PIC IRQs 0-11 */ + openpic_set_sources(32, 12, OpenPIC_Addr + 0x10000); + + /* + * Let openpic interrupts starting from an offset, to + * leave space for cascading interrupts underneath. + */ + openpic_init(MPC85xx_OPENPIC_IRQ_OFFSET); + + /* Setup CPM2 PIC */ + cpm2_init_IRQ(); + + setup_irq(MPC85xx_IRQ_CPM, &cpm2_irqaction); + + return; +} + +static int +gp3_show_cpuinfo(struct seq_file *m) +{ + uint pvid, svid, phid1; + bd_t *binfo = (bd_t *) __res; + uint memsize; + unsigned int freq; + extern unsigned long total_memory; /* in mm/init */ + + /* get the core frequency */ + freq = binfo->bi_intfreq; + + pvid = mfspr(SPRN_PVR); + svid = mfspr(SPRN_SVR); + + memsize = total_memory; + + seq_printf(m, "Vendor\t\t: RPC Electronics STx \n"); + seq_printf(m, "Machine\t\t: GP3 - MPC%s\n", cur_ppc_sys_spec->ppc_sys_name); + seq_printf(m, "bus freq\t: %u.%.6u MHz\n", freq / 1000000, + freq % 1000000); + seq_printf(m, "PVR\t\t: 0x%x\n", pvid); + seq_printf(m, "SVR\t\t: 0x%x\n", svid); + + /* Display cpu Pll setting */ + phid1 = mfspr(SPRN_HID1); + seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); + + /* Display the amount of memory */ + seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); + + return 0; +} + +#ifdef CONFIG_PCI +int mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel, + unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {PIRQA, PIRQB, PIRQC, PIRQD}, + {PIRQD, PIRQA, PIRQB, PIRQC}, + {PIRQC, PIRQD, PIRQA, PIRQB}, + {PIRQB, PIRQC, PIRQD, PIRQA}, + }; + + const long min_idsel = 12, max_idsel = 15, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +} + +int mpc85xx_exclude_device(u_char bus, u_char devfn) +{ + if (bus == 0 && PCI_SLOT(devfn) == 0) + return PCIBIOS_DEVICE_NOT_FOUND; + else + return PCIBIOS_SUCCESSFUL; +} +#endif /* CONFIG_PCI */ + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + /* parse_bootinfo must always be called first */ + parse_bootinfo(find_bootinfo()); + + /* + * If we were passed in a board information, copy it into the + * residual data area. + */ + if (r3) { + memcpy((void *) __res, (void *) (r3 + KERNELBASE), + sizeof (bd_t)); + + } +#if defined(CONFIG_BLK_DEV_INITRD) + /* + * If the init RAM disk has been configured in, and there's a valid + * starting address for it, set it up. + */ + if (r4) { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif /* CONFIG_BLK_DEV_INITRD */ + + /* Copy the kernel command line arguments to a safe place. */ + + if (r6) { + *(char *) (r7 + KERNELBASE) = 0; + strcpy(cmd_line, (char *) (r6 + KERNELBASE)); + } + + identify_ppc_sys_by_id(mfspr(SPRN_SVR)); + + /* setup the PowerPC module struct */ + ppc_md.setup_arch = gp3_setup_arch; + ppc_md.show_cpuinfo = gp3_show_cpuinfo; + + ppc_md.init_IRQ = gp3_init_IRQ; + ppc_md.get_irq = openpic_get_irq; + + ppc_md.restart = mpc85xx_restart; + ppc_md.power_off = mpc85xx_power_off; + ppc_md.halt = mpc85xx_halt; + + ppc_md.find_end_of_memory = mpc85xx_find_end_of_memory; + + ppc_md.calibrate_decr = mpc85xx_calibrate_decr; + + if (ppc_md.progress) + ppc_md.progress("platform_init(): exit", 0); + + return; +} diff --git a/arch/ppc/platforms/85xx/stx_gp3.h b/arch/ppc/platforms/85xx/stx_gp3.h new file mode 100644 index 00000000000..7bcc6c35a41 --- /dev/null +++ b/arch/ppc/platforms/85xx/stx_gp3.h @@ -0,0 +1,74 @@ +/* + * arch/ppc/platforms/stx8560_gp3.h + * + * STx GP3 board definitions + * + * Dan Malek (dan@embeddededge.com) + * Copyright 2004 Embedded Edge, LLC + * + * Ported to 2.6, Matt Porter <mporter@kernel.crashing.org> + * Copyright 2004-2005 MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __MACH_STX_GP3_H +#define __MACH_STX_GP3_H + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/seq_file.h> +#include <asm/ppcboot.h> + +#define BOARD_CCSRBAR ((uint)0xe0000000) +#define CCSRBAR_SIZE ((uint)1024*1024) + +#define CPM_MAP_ADDR (CCSRBAR + MPC85xx_CPM_OFFSET) + +#define BCSR_ADDR ((uint)0xfc000000) +#define BCSR_SIZE ((uint)(16 * 1024)) + +#define BCSR_TSEC1_RESET 0x00000080 +#define BCSR_TSEC2_RESET 0x00000040 +#define BCSR_LED1 0x00000008 +#define BCSR_LED2 0x00000004 +#define BCSR_LED3 0x00000002 +#define BCSR_LED4 0x00000001 + +extern void mpc85xx_setup_hose(void) __init; +extern void mpc85xx_restart(char *cmd); +extern void mpc85xx_power_off(void); +extern void mpc85xx_halt(void); +extern int mpc85xx_show_cpuinfo(struct seq_file *m); +extern void mpc85xx_init_IRQ(void) __init; +extern unsigned long mpc85xx_find_end_of_memory(void) __init; +extern void mpc85xx_calibrate_decr(void) __init; + +#define PCI_CFG_ADDR_OFFSET (0x8000) +#define PCI_CFG_DATA_OFFSET (0x8004) + +/* PCI interrupt controller */ +#define PIRQA MPC85xx_IRQ_EXT1 +#define PIRQB MPC85xx_IRQ_EXT2 +#define PIRQC MPC85xx_IRQ_EXT3 +#define PIRQD MPC85xx_IRQ_EXT4 +#define PCI_MIN_IDSEL 16 +#define PCI_MAX_IDSEL 19 +#define PCI_IRQ_SLOT 4 + +#define MPC85XX_PCI1_LOWER_IO 0x00000000 +#define MPC85XX_PCI1_UPPER_IO 0x00ffffff + +#define MPC85XX_PCI1_LOWER_MEM 0x80000000 +#define MPC85XX_PCI1_UPPER_MEM 0x9fffffff + +#define MPC85XX_PCI1_IO_BASE 0xe2000000 +#define MPC85XX_PCI1_MEM_OFFSET 0x00000000 + +#define MPC85XX_PCI1_IO_SIZE 0x01000000 + +#endif /* __MACH_STX_GP3_H */ diff --git a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile new file mode 100644 index 00000000000..5488a053f41 --- /dev/null +++ b/arch/ppc/platforms/Makefile @@ -0,0 +1,53 @@ +# +# Makefile for the linux kernel. +# + +# Extra CFLAGS so we don't have to do relative includes +CFLAGS_pmac_setup.o += -Iarch/$(ARCH)/mm + +obj-$(CONFIG_APUS) += apus_setup.o +ifeq ($(CONFIG_APUS),y) +obj-$(CONFIG_PCI) += apus_pci.o +endif +obj-$(CONFIG_PPC_PMAC) += pmac_pic.o pmac_setup.o pmac_time.o \ + pmac_feature.o pmac_pci.o pmac_sleep.o \ + pmac_low_i2c.o pmac_cache.o +obj-$(CONFIG_PPC_CHRP) += chrp_setup.o chrp_time.o chrp_pci.o \ + chrp_pegasos_eth.o +obj-$(CONFIG_PPC_PREP) += prep_pci.o prep_setup.o +ifeq ($(CONFIG_PPC_PMAC),y) +obj-$(CONFIG_NVRAM) += pmac_nvram.o +obj-$(CONFIG_CPU_FREQ_PMAC) += pmac_cpufreq.o +endif +obj-$(CONFIG_PMAC_BACKLIGHT) += pmac_backlight.o +obj-$(CONFIG_PREP_RESIDUAL) += residual.o +obj-$(CONFIG_ADIR) += adir_setup.o adir_pic.o adir_pci.o +obj-$(CONFIG_PQ2ADS) += pq2ads.o +obj-$(CONFIG_TQM8260) += tqm8260_setup.o +obj-$(CONFIG_CPCI690) += cpci690.o +obj-$(CONFIG_EV64260) += ev64260.o +obj-$(CONFIG_CHESTNUT) += chestnut.o +obj-$(CONFIG_GEMINI) += gemini_pci.o gemini_setup.o gemini_prom.o +obj-$(CONFIG_K2) += k2.o +obj-$(CONFIG_LOPEC) += lopec.o +obj-$(CONFIG_KATANA) += katana.o +obj-$(CONFIG_HDPU) += hdpu.o +obj-$(CONFIG_MCPN765) += mcpn765.o +obj-$(CONFIG_MENF1) += menf1_setup.o menf1_pci.o +obj-$(CONFIG_MVME5100) += mvme5100.o +obj-$(CONFIG_PAL4) += pal4_setup.o pal4_pci.o +obj-$(CONFIG_PCORE) += pcore.o +obj-$(CONFIG_POWERPMC250) += powerpmc250.o +obj-$(CONFIG_PPLUS) += pplus.o +obj-$(CONFIG_PRPMC750) += prpmc750.o +obj-$(CONFIG_PRPMC800) += prpmc800.o +obj-$(CONFIG_RADSTONE_PPC7D) += radstone_ppc7d.o +obj-$(CONFIG_SANDPOINT) += sandpoint.o +obj-$(CONFIG_SBC82xx) += sbc82xx.o +obj-$(CONFIG_SPRUCE) += spruce.o +obj-$(CONFIG_LITE5200) += lite5200.o + +ifeq ($(CONFIG_SMP),y) +obj-$(CONFIG_PPC_PMAC) += pmac_smp.o +obj-$(CONFIG_PPC_CHRP) += chrp_smp.o +endif diff --git a/arch/ppc/platforms/adir.h b/arch/ppc/platforms/adir.h new file mode 100644 index 00000000000..13a748b4695 --- /dev/null +++ b/arch/ppc/platforms/adir.h @@ -0,0 +1,95 @@ +/* + * arch/ppc/platforms/adir.h + * + * Definitions for SBS Adirondack board support + * + * By Michael Sokolov <msokolov@ivan.Harhan.ORG> + */ + +#ifndef __PPC_PLATFORMS_ADIR_H +#define __PPC_PLATFORMS_ADIR_H + +/* + * SBS Adirondack definitions + */ + +/* PPC physical address space layout. We use the one set up by the firmware. */ +#define ADIR_PCI32_MEM_BASE 0x80000000 +#define ADIR_PCI32_MEM_SIZE 0x20000000 +#define ADIR_PCI64_MEM_BASE 0xA0000000 +#define ADIR_PCI64_MEM_SIZE 0x20000000 +#define ADIR_PCI32_IO_BASE 0xC0000000 +#define ADIR_PCI32_IO_SIZE 0x10000000 +#define ADIR_PCI64_IO_BASE 0xD0000000 +#define ADIR_PCI64_IO_SIZE 0x10000000 +#define ADIR_PCI64_PHB 0xFF400000 +#define ADIR_PCI32_PHB 0xFF500000 + +#define ADIR_PCI64_CONFIG_ADDR (ADIR_PCI64_PHB + 0x000f8000) +#define ADIR_PCI64_CONFIG_DATA (ADIR_PCI64_PHB + 0x000f8010) + +#define ADIR_PCI32_CONFIG_ADDR (ADIR_PCI32_PHB + 0x000f8000) +#define ADIR_PCI32_CONFIG_DATA (ADIR_PCI32_PHB + 0x000f8010) + +/* System memory as seen from PCI */ +#define ADIR_PCI_SYS_MEM_BASE 0x80000000 + +/* Static virtual mapping of PCI I/O */ +#define ADIR_PCI32_VIRT_IO_BASE 0xFE000000 +#define ADIR_PCI32_VIRT_IO_SIZE 0x01000000 +#define ADIR_PCI64_VIRT_IO_BASE 0xFF000000 +#define ADIR_PCI64_VIRT_IO_SIZE 0x01000000 + +/* Registers */ +#define ADIR_NVRAM_RTC_ADDR 0x74 +#define ADIR_NVRAM_RTC_DATA 0x75 + +#define ADIR_BOARD_ID_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF0) +#define ADIR_CPLD1REV_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF1) +#define ADIR_CPLD2REV_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF2) +#define ADIR_FLASHCTL_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF3) +#define ADIR_CPC710_STAT_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF4) +#define ADIR_CLOCK_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF5) +#define ADIR_GPIO_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF8) +#define ADIR_MISC_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF9) +#define ADIR_LED_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFFA) + +#define ADIR_CLOCK_REG_PD 0x10 +#define ADIR_CLOCK_REG_SPREAD 0x08 +#define ADIR_CLOCK_REG_SEL133 0x04 +#define ADIR_CLOCK_REG_SEL1 0x02 +#define ADIR_CLOCK_REG_SEL0 0x01 + +#define ADIR_PROCA_INT_MASK (ADIR_PCI32_VIRT_IO_BASE + 0x0EFFF0) +#define ADIR_PROCB_INT_MASK (ADIR_PCI32_VIRT_IO_BASE + 0x0EFFF2) +#define ADIR_PROCA_INT_STAT (ADIR_PCI32_VIRT_IO_BASE + 0x0EFFF4) +#define ADIR_PROCB_INT_STAT (ADIR_PCI32_VIRT_IO_BASE + 0x0EFFF6) + +/* Linux IRQ numbers */ +#define ADIR_IRQ_NONE -1 +#define ADIR_IRQ_SERIAL2 3 +#define ADIR_IRQ_SERIAL1 4 +#define ADIR_IRQ_FDC 6 +#define ADIR_IRQ_PARALLEL 7 +#define ADIR_IRQ_VIA_AUDIO 10 +#define ADIR_IRQ_VIA_USB 11 +#define ADIR_IRQ_IDE0 14 +#define ADIR_IRQ_IDE1 15 +#define ADIR_IRQ_PCI0_INTA 16 +#define ADIR_IRQ_PCI0_INTB 17 +#define ADIR_IRQ_PCI0_INTC 18 +#define ADIR_IRQ_PCI0_INTD 19 +#define ADIR_IRQ_PCI1_INTA 20 +#define ADIR_IRQ_PCI1_INTB 21 +#define ADIR_IRQ_PCI1_INTC 22 +#define ADIR_IRQ_PCI1_INTD 23 +#define ADIR_IRQ_MBSCSI 24 /* motherboard SCSI */ +#define ADIR_IRQ_MBETH1 25 /* motherboard Ethernet 1 */ +#define ADIR_IRQ_MBETH0 26 /* motherboard Ethernet 0 */ +#define ADIR_IRQ_CPC710_INT1 27 +#define ADIR_IRQ_CPC710_INT2 28 +#define ADIR_IRQ_VT82C686_NMI 29 +#define ADIR_IRQ_VT82C686_INTR 30 +#define ADIR_IRQ_INTERPROC 31 + +#endif /* __PPC_PLATFORMS_ADIR_H */ diff --git a/arch/ppc/platforms/adir_pci.c b/arch/ppc/platforms/adir_pci.c new file mode 100644 index 00000000000..f94ac53e071 --- /dev/null +++ b/arch/ppc/platforms/adir_pci.c @@ -0,0 +1,247 @@ +/* + * arch/ppc/platforms/adir_pci.c + * + * PCI support for SBS Adirondack + * + * By Michael Sokolov <msokolov@ivan.Harhan.ORG> + * based on the K2 version by Matt Porter <mporter@mvista.com> + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/slab.h> + +#include <asm/byteorder.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/machdep.h> +#include <asm/pci-bridge.h> + +#include <syslib/cpc710.h> +#include "adir.h" + +#undef DEBUG +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif /* DEBUG */ + +static inline int __init +adir_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ +#define PCIIRQ(a,b,c,d) {ADIR_IRQ_##a,ADIR_IRQ_##b,ADIR_IRQ_##c,ADIR_IRQ_##d}, + struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); + /* + * The three PCI devices on the motherboard have dedicated lines to the + * CPLD interrupt controller, bypassing the standard PCI INTA-D and the + * PC interrupt controller. All other PCI devices (slots) have usual + * staggered INTA-D lines, resulting in 8 lines total (PCI0 INTA-D and + * PCI1 INTA-D). All 8 go to the CPLD interrupt controller. PCI0 INTA-D + * also go to the south bridge, so we have the option of taking them + * via the CPLD interrupt controller or via the south bridge 8259 + * 8258 thingy. PCI1 INTA-D can only be taken via the CPLD interrupt + * controller. We take all PCI interrupts via the CPLD interrupt + * controller as recommended by SBS. + * + * We also have some monkey business with the PCI devices within the + * VT82C686B south bridge itself. This chip actually has 7 functions on + * its IDSEL. Function 0 is the actual south bridge, function 1 is IDE, + * and function 4 is some special stuff. The other 4 functions are just + * regular PCI devices bundled in the chip. 2 and 3 are USB UHCIs and 5 + * and 6 are audio (not supported on the Adirondack). + * + * This is where the monkey business begins. PCI devices are supposed + * to signal normal PCI interrupts. But the 4 functions in question are + * located in the south bridge chip, which is designed with the + * assumption that it will be fielding PCI INTA-D interrupts rather + * than generating them. Here's what it does. Each of the functions in + * question routes its interrupt to one of the IRQs on the 8259 thingy. + * Which one? It looks at the Interrupt Line register in the PCI config + * space, even though the PCI spec says it's for BIOS/OS interaction + * only. + * + * How do we deal with this? We take these interrupts via 8259 IRQs as + * we have to. We return the desired IRQ numbers from this routine when + * called for the functions in question. The PCI scan code will then + * stick our return value into the Interrupt Line register in the PCI + * config space, and the interrupt will actually go there. We identify + * these functions within the south bridge IDSEL by their interrupt pin + * numbers, as the VT82C686B has 04 in the Interrupt Pin register for + * USB and 03 for audio. + */ + if (!hose->index) { + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + /* south bridge */ PCIIRQ(IDE0, NONE, VIA_AUDIO, VIA_USB) + /* Ethernet 0 */ PCIIRQ(MBETH0, MBETH0, MBETH0, MBETH0) + /* PCI0 slot 1 */ PCIIRQ(PCI0_INTB, PCI0_INTC, PCI0_INTD, PCI0_INTA) + /* PCI0 slot 2 */ PCIIRQ(PCI0_INTC, PCI0_INTD, PCI0_INTA, PCI0_INTB) + /* PCI0 slot 3 */ PCIIRQ(PCI0_INTD, PCI0_INTA, PCI0_INTB, PCI0_INTC) + }; + const long min_idsel = 3, max_idsel = 7, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; + } else { + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + /* Ethernet 1 */ PCIIRQ(MBETH1, MBETH1, MBETH1, MBETH1) + /* SCSI */ PCIIRQ(MBSCSI, MBSCSI, MBSCSI, MBSCSI) + /* PCI1 slot 1 */ PCIIRQ(PCI1_INTB, PCI1_INTC, PCI1_INTD, PCI1_INTA) + /* PCI1 slot 2 */ PCIIRQ(PCI1_INTC, PCI1_INTD, PCI1_INTA, PCI1_INTB) + /* PCI1 slot 3 */ PCIIRQ(PCI1_INTD, PCI1_INTA, PCI1_INTB, PCI1_INTC) + }; + const long min_idsel = 3, max_idsel = 7, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; + } +#undef PCIIRQ +} + +static void +adir_pcibios_fixup_resources(struct pci_dev *dev) +{ + int i; + + if ((dev->vendor == PCI_VENDOR_ID_IBM) && + (dev->device == PCI_DEVICE_ID_IBM_CPC710_PCI64)) + { + DBG("Fixup CPC710 resources\n"); + for (i=0; i<DEVICE_COUNT_RESOURCE; i++) + { + dev->resource[i].start = 0; + dev->resource[i].end = 0; + } + } +} + +/* + * CPC710 DD3 has an errata causing it to hang the system if a type 0 config + * cycle is attempted on its PCI32 interface with a device number > 21. + * CPC710's PCI bridges map device numbers 1 through 21 to AD11 through AD31. + * Per the PCI spec it MUST accept all other device numbers and do nothing, and + * software MUST scan all device numbers without assuming how IDSELs are + * mapped. However, as the CPC710 DD3's errata causes such correct scanning + * procedure to hang the system, we have no choice but to introduce this hack + * of knowingly avoiding device numbers > 21 on PCI0, + */ +static int +adir_exclude_device(u_char bus, u_char devfn) +{ + if ((bus == 0) && (PCI_SLOT(devfn) > 21)) + return PCIBIOS_DEVICE_NOT_FOUND; + else + return PCIBIOS_SUCCESSFUL; +} + +void adir_find_bridges(void) +{ + struct pci_controller *hose_a, *hose_b; + + /* Setup PCI32 hose */ + hose_a = pcibios_alloc_controller(); + if (!hose_a) + return; + + hose_a->first_busno = 0; + hose_a->last_busno = 0xff; + hose_a->pci_mem_offset = ADIR_PCI32_MEM_BASE; + hose_a->io_space.start = 0; + hose_a->io_space.end = ADIR_PCI32_VIRT_IO_SIZE - 1; + hose_a->mem_space.start = 0; + hose_a->mem_space.end = ADIR_PCI32_MEM_SIZE - 1; + hose_a->io_resource.start = 0; + hose_a->io_resource.end = ADIR_PCI32_VIRT_IO_SIZE - 1; + hose_a->io_resource.flags = IORESOURCE_IO; + hose_a->mem_resources[0].start = ADIR_PCI32_MEM_BASE; + hose_a->mem_resources[0].end = ADIR_PCI32_MEM_BASE + + ADIR_PCI32_MEM_SIZE - 1; + hose_a->mem_resources[0].flags = IORESOURCE_MEM; + hose_a->io_base_phys = ADIR_PCI32_IO_BASE; + hose_a->io_base_virt = (void *) ADIR_PCI32_VIRT_IO_BASE; + + ppc_md.pci_exclude_device = adir_exclude_device; + setup_indirect_pci(hose_a, ADIR_PCI32_CONFIG_ADDR, + ADIR_PCI32_CONFIG_DATA); + + /* Initialize PCI32 bus registers */ + early_write_config_byte(hose_a, + hose_a->first_busno, + PCI_DEVFN(0, 0), + CPC710_BUS_NUMBER, + hose_a->first_busno); + early_write_config_byte(hose_a, + hose_a->first_busno, + PCI_DEVFN(0, 0), + CPC710_SUB_BUS_NUMBER, + hose_a->last_busno); + + hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno); + + /* Write out correct max subordinate bus number for hose A */ + early_write_config_byte(hose_a, + hose_a->first_busno, + PCI_DEVFN(0, 0), + CPC710_SUB_BUS_NUMBER, + hose_a->last_busno); + + /* Setup PCI64 hose */ + hose_b = pcibios_alloc_controller(); + if (!hose_b) + return; + + hose_b->first_busno = hose_a->last_busno + 1; + hose_b->last_busno = 0xff; + hose_b->pci_mem_offset = ADIR_PCI64_MEM_BASE; + hose_b->io_space.start = 0; + hose_b->io_space.end = ADIR_PCI64_VIRT_IO_SIZE - 1; + hose_b->mem_space.start = 0; + hose_b->mem_space.end = ADIR_PCI64_MEM_SIZE - 1; + hose_b->io_resource.start = 0; + hose_b->io_resource.end = ADIR_PCI64_VIRT_IO_SIZE - 1; + hose_b->io_resource.flags = IORESOURCE_IO; + hose_b->mem_resources[0].start = ADIR_PCI64_MEM_BASE; + hose_b->mem_resources[0].end = ADIR_PCI64_MEM_BASE + + ADIR_PCI64_MEM_SIZE - 1; + hose_b->mem_resources[0].flags = IORESOURCE_MEM; + hose_b->io_base_phys = ADIR_PCI64_IO_BASE; + hose_b->io_base_virt = (void *) ADIR_PCI64_VIRT_IO_BASE; + + setup_indirect_pci(hose_b, ADIR_PCI64_CONFIG_ADDR, + ADIR_PCI64_CONFIG_DATA); + + /* Initialize PCI64 bus registers */ + early_write_config_byte(hose_b, + 0, + PCI_DEVFN(0, 0), + CPC710_SUB_BUS_NUMBER, + 0xff); + + early_write_config_byte(hose_b, + 0, + PCI_DEVFN(0, 0), + CPC710_BUS_NUMBER, + hose_b->first_busno); + + hose_b->last_busno = pciauto_bus_scan(hose_b, + hose_b->first_busno); + + /* Write out correct max subordinate bus number for hose B */ + early_write_config_byte(hose_b, + hose_b->first_busno, + PCI_DEVFN(0, 0), + CPC710_SUB_BUS_NUMBER, + hose_b->last_busno); + + ppc_md.pcibios_fixup = NULL; + ppc_md.pcibios_fixup_resources = adir_pcibios_fixup_resources; + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = adir_map_irq; +} diff --git a/arch/ppc/platforms/adir_pic.c b/arch/ppc/platforms/adir_pic.c new file mode 100644 index 00000000000..9947cba52af --- /dev/null +++ b/arch/ppc/platforms/adir_pic.c @@ -0,0 +1,130 @@ +/* + * arch/ppc/platforms/adir_pic.c + * + * Interrupt controller support for SBS Adirondack + * + * By Michael Sokolov <msokolov@ivan.Harhan.ORG> + * based on the K2 and SCM versions by Matt Porter <mporter@mvista.com> + */ + +#include <linux/stddef.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/interrupt.h> + +#include <asm/io.h> +#include <asm/i8259.h> +#include "adir.h" + +static void adir_onboard_pic_enable(unsigned int irq); +static void adir_onboard_pic_disable(unsigned int irq); + +__init static void +adir_onboard_pic_init(void) +{ + volatile u_short *maskreg = (volatile u_short *) ADIR_PROCA_INT_MASK; + + /* Disable all Adirondack onboard interrupts */ + out_be16(maskreg, 0xFFFF); +} + +static int +adir_onboard_pic_get_irq(void) +{ + volatile u_short *statreg = (volatile u_short *) ADIR_PROCA_INT_STAT; + int irq; + u_short int_status, int_test; + + int_status = in_be16(statreg); + for (irq = 0, int_test = 1; irq < 16; irq++, int_test <<= 1) { + if (int_status & int_test) + break; + } + + if (irq == 16) + return -1; + + return (irq+16); +} + +static void +adir_onboard_pic_enable(unsigned int irq) +{ + volatile u_short *maskreg = (volatile u_short *) ADIR_PROCA_INT_MASK; + + /* Change irq to Adirondack onboard native value */ + irq -= 16; + + /* Enable requested irq number */ + out_be16(maskreg, in_be16(maskreg) & ~(1 << irq)); +} + +static void +adir_onboard_pic_disable(unsigned int irq) +{ + volatile u_short *maskreg = (volatile u_short *) ADIR_PROCA_INT_MASK; + + /* Change irq to Adirondack onboard native value */ + irq -= 16; + + /* Disable requested irq number */ + out_be16(maskreg, in_be16(maskreg) | (1 << irq)); +} + +static struct hw_interrupt_type adir_onboard_pic = { + " ADIR PIC ", + NULL, + NULL, + adir_onboard_pic_enable, /* unmask */ + adir_onboard_pic_disable, /* mask */ + adir_onboard_pic_disable, /* mask and ack */ + NULL, + NULL +}; + +static struct irqaction noop_action = { + .handler = no_action, + .flags = SA_INTERRUPT, + .mask = CPU_MASK_NONE, + .name = "82c59 primary cascade", +}; + +/* + * Linux interrupt values are assigned as follows: + * + * 0-15 VT82C686 8259 interrupts + * 16-31 Adirondack CPLD interrupts + */ +__init void +adir_init_IRQ(void) +{ + int i; + + /* Initialize the cascaded 8259's on the VT82C686 */ + for (i=0; i<16; i++) + irq_desc[i].handler = &i8259_pic; + i8259_init(NULL); + + /* Initialize Adirondack CPLD PIC and enable 8259 interrupt cascade */ + for (i=16; i<32; i++) + irq_desc[i].handler = &adir_onboard_pic; + adir_onboard_pic_init(); + + /* Enable 8259 interrupt cascade */ + setup_irq(ADIR_IRQ_VT82C686_INTR, &noop_action); +} + +int +adir_get_irq(struct pt_regs *regs) +{ + int irq; + + if ((irq = adir_onboard_pic_get_irq()) < 0) + return irq; + + if (irq == ADIR_IRQ_VT82C686_INTR) + irq = i8259_irq(regs); + + return irq; +} diff --git a/arch/ppc/platforms/adir_setup.c b/arch/ppc/platforms/adir_setup.c new file mode 100644 index 00000000000..6a6754ee061 --- /dev/null +++ b/arch/ppc/platforms/adir_setup.c @@ -0,0 +1,210 @@ +/* + * arch/ppc/platforms/adir_setup.c + * + * Board setup routines for SBS Adirondack + * + * By Michael Sokolov <msokolov@ivan.Harhan.ORG> + * based on the K2 version by Matt Porter <mporter@mvista.com> + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/types.h> +#include <linux/major.h> +#include <linux/initrd.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/ide.h> +#include <linux/seq_file.h> +#include <linux/root_dev.h> + +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/machdep.h> +#include <asm/time.h> +#include <asm/todc.h> +#include <asm/bootinfo.h> + +#include "adir.h" + +extern void adir_init_IRQ(void); +extern int adir_get_irq(struct pt_regs *); +extern void adir_find_bridges(void); +extern unsigned long loops_per_jiffy; + +static unsigned int cpu_750cx[16] = { + 5, 15, 14, 0, 4, 13, 0, 9, 6, 11, 8, 10, 16, 12, 7, 0 +}; + +static int +adir_get_bus_speed(void) +{ + if (!(*((u_char *) ADIR_CLOCK_REG) & ADIR_CLOCK_REG_SEL133)) + return 100000000; + else + return 133333333; +} + +static int +adir_get_cpu_speed(void) +{ + unsigned long hid1; + int cpu_speed; + + hid1 = mfspr(SPRN_HID1) >> 28; + + hid1 = cpu_750cx[hid1]; + + cpu_speed = adir_get_bus_speed()*hid1/2; + return cpu_speed; +} + +static void __init +adir_calibrate_decr(void) +{ + int freq, divisor = 4; + + /* determine processor bus speed */ + freq = adir_get_bus_speed(); + tb_ticks_per_jiffy = freq / HZ / divisor; + tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000); +} + +static int +adir_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "vendor\t\t: SBS\n"); + seq_printf(m, "machine\t\t: Adirondack\n"); + seq_printf(m, "cpu speed\t: %dMhz\n", adir_get_cpu_speed()/1000000); + seq_printf(m, "bus speed\t: %dMhz\n", adir_get_bus_speed()/1000000); + seq_printf(m, "memory type\t: SDRAM\n"); + + return 0; +} + +extern char cmd_line[]; + +TODC_ALLOC(); + +static void __init +adir_setup_arch(void) +{ + unsigned int cpu; + + /* Setup TODC access */ + TODC_INIT(TODC_TYPE_MC146818, ADIR_NVRAM_RTC_ADDR, 0, + ADIR_NVRAM_RTC_DATA, 8); + + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000/HZ; + + /* Setup PCI host bridges */ + adir_find_bridges(); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_SDA1; +#endif + + /* Identify the system */ + printk("System Identification: SBS Adirondack - PowerPC 750CXe @ %d Mhz\n", adir_get_cpu_speed()/1000000); + printk("SBS Adirondack port (C) 2001 SBS Technologies, Inc.\n"); + + /* Identify the CPU manufacturer */ + cpu = mfspr(SPRN_PVR); + printk("CPU manufacturer: IBM [rev=%04x]\n", (cpu & 0xffff)); +} + +static void +adir_restart(char *cmd) +{ + local_irq_disable(); + /* SRR0 has system reset vector, SRR1 has default MSR value */ + /* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */ + __asm__ __volatile__ + ("lis 3,0xfff0\n\t" + "ori 3,3,0x0100\n\t" + "mtspr 26,3\n\t" + "li 3,0\n\t" + "mtspr 27,3\n\t" + "rfi\n\t"); + for(;;); +} + +static void +adir_power_off(void) +{ + for(;;); +} + +static void +adir_halt(void) +{ + adir_restart(NULL); +} + +static unsigned long __init +adir_find_end_of_memory(void) +{ + return boot_mem_size; +} + +static void __init +adir_map_io(void) +{ + io_block_mapping(ADIR_PCI32_VIRT_IO_BASE, ADIR_PCI32_IO_BASE, + ADIR_PCI32_VIRT_IO_SIZE, _PAGE_IO); + io_block_mapping(ADIR_PCI64_VIRT_IO_BASE, ADIR_PCI64_IO_BASE, + ADIR_PCI64_VIRT_IO_SIZE, _PAGE_IO); +} + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + /* + * On the Adirondack we use bi_recs and pass the pointer to them in R3. + */ + parse_bootinfo((struct bi_record *) (r3 + KERNELBASE)); + + /* Remember, isa_io_base is virtual but isa_mem_base is physical! */ + isa_io_base = ADIR_PCI32_VIRT_IO_BASE; + isa_mem_base = ADIR_PCI32_MEM_BASE; + pci_dram_offset = ADIR_PCI_SYS_MEM_BASE; + + ppc_md.setup_arch = adir_setup_arch; + ppc_md.show_cpuinfo = adir_show_cpuinfo; + ppc_md.irq_canonicalize = NULL; + ppc_md.init_IRQ = adir_init_IRQ; + ppc_md.get_irq = adir_get_irq; + ppc_md.init = NULL; + + ppc_md.find_end_of_memory = adir_find_end_of_memory; + ppc_md.setup_io_mappings = adir_map_io; + + ppc_md.restart = adir_restart; + ppc_md.power_off = adir_power_off; + ppc_md.halt = adir_halt; + + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.nvram_read_val = todc_mc146818_read_val; + ppc_md.nvram_write_val = todc_mc146818_write_val; + ppc_md.calibrate_decr = adir_calibrate_decr; +} diff --git a/arch/ppc/platforms/apus_pci.c b/arch/ppc/platforms/apus_pci.c new file mode 100644 index 00000000000..33dad6db824 --- /dev/null +++ b/arch/ppc/platforms/apus_pci.c @@ -0,0 +1,208 @@ +/* + * Copyright (C) Michel Dänzer <michdaen@iiic.ethz.ch> + * + * APUS PCI routines. + * + * Currently, only B/CVisionPPC cards (Permedia2) are supported. + * + * Thanks to Geert Uytterhoeven for the idea: + * Read values from given config space(s) for the first devices, -1 otherwise + * + */ + +#include <linux/config.h> +#ifdef CONFIG_AMIGA + +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/string.h> +#include <linux/init.h> + +#include <asm/io.h> +#include <asm/pci-bridge.h> +#include <asm/machdep.h> + +#include "apus_pci.h" + + +/* These definitions are mostly adapted from pm2fb.c */ + +#undef APUS_PCI_MASTER_DEBUG +#ifdef APUS_PCI_MASTER_DEBUG +#define DPRINTK(a,b...) printk(KERN_DEBUG "apus_pci: %s: " a, __FUNCTION__ , ## b) +#else +#define DPRINTK(a,b...) +#endif + +/* + * The _DEFINITIVE_ memory mapping/unmapping functions. + * This is due to the fact that they're changing soooo often... + */ +#define DEFW() wmb() +#define DEFR() rmb() +#define DEFRW() mb() + +#define DEVNO(d) ((d)>>3) +#define FNNO(d) ((d)&7) + + +extern unsigned long powerup_PCI_present; + +static struct pci_controller *apus_hose; + + +void *pci_io_base(unsigned int bus) +{ + return 0; +} + + +int +apus_pcibios_read_config(struct pci_bus *bus, int devfn, int offset, + int len, u32 *val) +{ + int fnno = FNNO(devfn); + int devno = DEVNO(devfn); + volatile unsigned char *cfg_data; + + if (bus->number > 0 || devno != 1) { + *val = ~0; + return PCIBIOS_DEVICE_NOT_FOUND; + } + /* base address + function offset + offset ^ endianness conversion */ + /* XXX the fnno<<5 bit seems wacky -- paulus */ + cfg_data = apus_hose->cfg_data + (fnno<<5) + (offset ^ (len - 1)); + switch (len) { + case 1: + *val = readb(cfg_data); + break; + case 2: + *val = readw(cfg_data); + break; + default: + *val = readl(cfg_data); + break; + } + + DPRINTK("read b: 0x%x, d: 0x%x, f: 0x%x, o: 0x%x, l: %d, v: 0x%x\n", + bus->number, devfn>>3, devfn&7, offset, len, *val); + return PCIBIOS_SUCCESSFUL; +} + +int +apus_pcibios_write_config(struct pci_bus *bus, int devfn, int offset, + int len, u32 *val) +{ + int fnno = FNNO(devfn); + int devno = DEVNO(devfn); + volatile unsigned char *cfg_data; + + if (bus->number > 0 || devno != 1) { + return PCIBIOS_DEVICE_NOT_FOUND; + } + /* base address + function offset + offset ^ endianness conversion */ + /* XXX the fnno<<5 bit seems wacky -- paulus */ + cfg_data = apus_hose->cfg_data + (fnno<<5) + (offset ^ (len - 1)); + switch (len) { + case 1: + writeb(val, cfg_data); DEFW(); + break; + case 2: + writew(val, cfg_data); DEFW(); + break; + default: + writel(val, cfg_data); DEFW(); + break; + } + + DPRINTK("write b: 0x%x, d: 0x%x, f: 0x%x, o: 0x%x, l: %d, v: 0x%x\n", + bus->number, devfn>>3, devfn&7, offset, len, val); + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops apus_pci_ops = { + apus_pcibios_read_config, + apus_pcibios_write_config +}; + +static struct resource pci_mem = { "B/CVisionPPC PCI mem", CVPPC_FB_APERTURE_ONE, CVPPC_PCI_CONFIG, IORESOURCE_MEM }; + +void __init +apus_pcibios_fixup(void) +{ +/* struct pci_dev *dev = pci_find_slot(0, 1<<3); + unsigned int reg, val, offset;*/ + + /* FIXME: interrupt? */ + /*dev->interrupt = xxx;*/ + + request_resource(&iomem_resource, &pci_mem); + printk("%s: PCI mem resource requested\n", __FUNCTION__); +} + +static void __init apus_pcibios_fixup_bus(struct pci_bus *bus) +{ + bus->resource[1] = &pci_mem; +} + + +/* + * This is from pm2fb.c again + * + * Check if PCI (B/CVisionPPC) is available, initialize it and set up + * the pcibios_* pointers + */ + + +void __init +apus_setup_pci_ptrs(void) +{ + if (!powerup_PCI_present) { + DPRINTK("no PCI bridge detected\n"); + return; + } + DPRINTK("Phase5 B/CVisionPPC PCI bridge detected.\n"); + + apus_hose = pcibios_alloc_controller(); + if (!apus_hose) { + printk("apus_pci: Can't allocate PCI controller structure\n"); + return; + } + + if (!(apus_hose->cfg_data = ioremap(CVPPC_PCI_CONFIG, 256))) { + printk("apus_pci: unable to map PCI config region\n"); + return; + } + + if (!(apus_hose->cfg_addr = ioremap(CSPPC_PCI_BRIDGE, 256))) { + printk("apus_pci: unable to map PCI bridge\n"); + return; + } + + writel(CSPPCF_BRIDGE_BIG_ENDIAN, apus_hose->cfg_addr + CSPPC_BRIDGE_ENDIAN); + DEFW(); + + writel(CVPPC_REGS_REGION, apus_hose->cfg_data+ PCI_BASE_ADDRESS_0); + DEFW(); + writel(CVPPC_FB_APERTURE_ONE, apus_hose->cfg_data + PCI_BASE_ADDRESS_1); + DEFW(); + writel(CVPPC_FB_APERTURE_TWO, apus_hose->cfg_data + PCI_BASE_ADDRESS_2); + DEFW(); + writel(CVPPC_ROM_ADDRESS, apus_hose->cfg_data + PCI_ROM_ADDRESS); + DEFW(); + + writel(0xef000000 | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER, apus_hose->cfg_data + PCI_COMMAND); + DEFW(); + + apus_hose->first_busno = 0; + apus_hose->last_busno = 0; + apus_hose->ops = &apus_pci_ops; + ppc_md.pcibios_fixup = apus_pcibios_fixup; + ppc_md.pcibios_fixup_bus = apus_pcibios_fixup_bus; + + return; +} + +#endif /* CONFIG_AMIGA */ diff --git a/arch/ppc/platforms/apus_pci.h b/arch/ppc/platforms/apus_pci.h new file mode 100644 index 00000000000..f15974ae018 --- /dev/null +++ b/arch/ppc/platforms/apus_pci.h @@ -0,0 +1,34 @@ +/* + * Phase5 CybervisionPPC (TVP4020) definitions for the Permedia2 framebuffer + * driver. + * + * Copyright (c) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT) + * -------------------------------------------------------------------------- + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + */ + +#ifndef APUS_PCI_H +#define APUS_PCI_H + + +#define CSPPC_PCI_BRIDGE 0xfffe0000 +#define CSPPC_BRIDGE_ENDIAN 0x0000 +#define CSPPC_BRIDGE_INT 0x0010 + +#define CVPPC_PCI_CONFIG 0xfffc0000 +#define CVPPC_ROM_ADDRESS 0xe2000001 +#define CVPPC_REGS_REGION 0xef000000 +#define CVPPC_FB_APERTURE_ONE 0xe0000000 +#define CVPPC_FB_APERTURE_TWO 0xe1000000 +#define CVPPC_FB_SIZE 0x00800000 + +/* CVPPC_BRIDGE_ENDIAN */ +#define CSPPCF_BRIDGE_BIG_ENDIAN 0x02 + +/* CVPPC_BRIDGE_INT */ +#define CSPPCF_BRIDGE_ACTIVE_INT2 0x01 + + +#endif /* APUS_PCI_H */ diff --git a/arch/ppc/platforms/apus_setup.c b/arch/ppc/platforms/apus_setup.c new file mode 100644 index 00000000000..2f74fde98eb --- /dev/null +++ b/arch/ppc/platforms/apus_setup.c @@ -0,0 +1,815 @@ +/* + * arch/ppc/platforms/apus_setup.c + * + * Copyright (C) 1998, 1999 Jesper Skov + * + * Basically what is needed to replace functionality found in + * arch/m68k allowing Amiga drivers to work under APUS. + * Bits of code and/or ideas from arch/m68k and arch/ppc files. + * + * TODO: + * This file needs a *really* good cleanup. Restructure and optimize. + * Make sure it can be compiled for non-APUS configs. Begin to move + * Amiga specific stuff into mach/amiga. + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/initrd.h> +#include <linux/seq_file.h> + +/* Needs INITSERIAL call in head.S! */ +#undef APUS_DEBUG + +#include <asm/bootinfo.h> +#include <asm/setup.h> +#include <asm/amigahw.h> +#include <asm/amigaints.h> +#include <asm/amigappc.h> +#include <asm/pgtable.h> +#include <asm/dma.h> +#include <asm/machdep.h> +#include <asm/time.h> + +unsigned long m68k_machtype; +char debug_device[6] = ""; + +extern void amiga_init_IRQ(void); + +extern void apus_setup_pci_ptrs(void); + +void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata = NULL; +/* machine dependent irq functions */ +void (*mach_init_IRQ) (void) __initdata = NULL; +void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL; +void (*mach_get_model) (char *model) = NULL; +int (*mach_get_hardware_list) (char *buffer) = NULL; +int (*mach_get_irq_list) (struct seq_file *, void *) = NULL; +void (*mach_process_int) (int, struct pt_regs *) = NULL; +/* machine dependent timer functions */ +unsigned long (*mach_gettimeoffset) (void); +void (*mach_gettod) (int*, int*, int*, int*, int*, int*); +int (*mach_hwclk) (int, struct hwclk_time*) = NULL; +int (*mach_set_clock_mmss) (unsigned long) = NULL; +void (*mach_reset)( void ); +long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */ +#if defined(CONFIG_AMIGA_FLOPPY) +void (*mach_floppy_setup) (char *, int *) __initdata = NULL; +#endif +#ifdef CONFIG_HEARTBEAT +void (*mach_heartbeat) (int) = NULL; +extern void apus_heartbeat (void); +#endif + +extern unsigned long amiga_model; +extern unsigned decrementer_count;/* count value for 1e6/HZ microseconds */ +extern unsigned count_period_num; /* 1 decrementer count equals */ +extern unsigned count_period_den; /* count_period_num / count_period_den us */ + +int num_memory = 0; +struct mem_info memory[NUM_MEMINFO];/* memory description */ +/* FIXME: Duplicate memory data to avoid conflicts with m68k shared code. */ +int m68k_realnum_memory = 0; +struct mem_info m68k_memory[NUM_MEMINFO];/* memory description */ + +struct mem_info ramdisk; + +extern void amiga_floppy_setup(char *, int *); +extern void config_amiga(void); + +static int __60nsram = 0; + +/* for cpuinfo */ +static int __bus_speed = 0; +static int __speed_test_failed = 0; + +/********************************************** COMPILE PROTECTION */ +/* Provide some stubs that links to Amiga specific functions. + * This allows CONFIG_APUS to be removed from generic PPC files while + * preventing link errors for other PPC targets. + */ +unsigned long apus_get_rtc_time(void) +{ +#ifdef CONFIG_APUS + extern unsigned long m68k_get_rtc_time(void); + + return m68k_get_rtc_time (); +#else + return 0; +#endif +} + +int apus_set_rtc_time(unsigned long nowtime) +{ +#ifdef CONFIG_APUS + extern int m68k_set_rtc_time(unsigned long nowtime); + + return m68k_set_rtc_time (nowtime); +#else + return 0; +#endif +} + +/*********************************************************** SETUP */ +/* From arch/m68k/kernel/setup.c. */ +void __init apus_setup_arch(void) +{ +#ifdef CONFIG_APUS + extern char cmd_line[]; + int i; + char *p, *q; + + /* Let m68k-shared code know it should do the Amiga thing. */ + m68k_machtype = MACH_AMIGA; + + /* Parse the command line for arch-specific options. + * For the m68k, this is currently only "debug=xxx" to enable printing + * certain kernel messages to some machine-specific device. */ + for( p = cmd_line; p && *p; ) { + i = 0; + if (!strncmp( p, "debug=", 6 )) { + strlcpy( debug_device, p+6, sizeof(debug_device) ); + if ((q = strchr( debug_device, ' ' ))) *q = 0; + i = 1; + } else if (!strncmp( p, "60nsram", 7 )) { + APUS_WRITE (APUS_REG_WAITSTATE, + REGWAITSTATE_SETRESET + |REGWAITSTATE_PPCR + |REGWAITSTATE_PPCW); + __60nsram = 1; + i = 1; + } + + if (i) { + /* option processed, delete it */ + if ((q = strchr( p, ' ' ))) + strcpy( p, q+1 ); + else + *p = 0; + } else { + if ((p = strchr( p, ' ' ))) ++p; + } + } + + config_amiga(); + +#if 0 /* Enable for logging - also include logging.o in Makefile rule */ + { +#define LOG_SIZE 4096 + void* base; + + /* Throw away some memory - the P5 firmare stomps on top + * of CHIP memory during bootup. + */ + amiga_chip_alloc(0x1000); + + base = amiga_chip_alloc(LOG_SIZE+sizeof(klog_data_t)); + LOG_INIT(base, base+sizeof(klog_data_t), LOG_SIZE); + } +#endif +#endif +} + +int +apus_show_cpuinfo(struct seq_file *m) +{ + extern int __map_without_bats; + extern unsigned long powerup_PCI_present; + + seq_printf(m, "machine\t\t: Amiga\n"); + seq_printf(m, "bus speed\t: %d%s", __bus_speed, + (__speed_test_failed) ? " [failed]\n" : "\n"); + seq_printf(m, "using BATs\t: %s\n", + (__map_without_bats) ? "No" : "Yes"); + seq_printf(m, "ram speed\t: %dns\n", (__60nsram) ? 60 : 70); + seq_printf(m, "PCI bridge\t: %s\n", + (powerup_PCI_present) ? "Yes" : "No"); + return 0; +} + +static void get_current_tb(unsigned long long *time) +{ + __asm __volatile ("1:mftbu 4 \n\t" + " mftb 5 \n\t" + " mftbu 6 \n\t" + " cmpw 4,6 \n\t" + " bne 1b \n\t" + " stw 4,0(%0)\n\t" + " stw 5,4(%0)\n\t" + : + : "r" (time) + : "r4", "r5", "r6"); +} + + +void apus_calibrate_decr(void) +{ +#ifdef CONFIG_APUS + unsigned long freq; + + /* This algorithm for determining the bus speed was + contributed by Ralph Schmidt. */ + unsigned long long start, stop; + int bus_speed; + int speed_test_failed = 0; + + { + unsigned long loop = amiga_eclock / 10; + + get_current_tb (&start); + while (loop--) { + unsigned char tmp; + + tmp = ciaa.pra; + } + get_current_tb (&stop); + } + + bus_speed = (((unsigned long)(stop-start))*10*4) / 1000000; + if (AMI_1200 == amiga_model) + bus_speed /= 2; + + if ((bus_speed >= 47) && (bus_speed < 53)) { + bus_speed = 50; + freq = 12500000; + } else if ((bus_speed >= 57) && (bus_speed < 63)) { + bus_speed = 60; + freq = 15000000; + } else if ((bus_speed >= 63) && (bus_speed < 69)) { + bus_speed = 67; + freq = 16666667; + } else { + printk ("APUS: Unable to determine bus speed (%d). " + "Defaulting to 50MHz", bus_speed); + bus_speed = 50; + freq = 12500000; + speed_test_failed = 1; + } + + /* Ease diagnostics... */ + { + extern int __map_without_bats; + extern unsigned long powerup_PCI_present; + + printk ("APUS: BATs=%d, BUS=%dMHz", + (__map_without_bats) ? 0 : 1, + bus_speed); + if (speed_test_failed) + printk ("[FAILED - please report]"); + + printk (", RAM=%dns, PCI bridge=%d\n", + (__60nsram) ? 60 : 70, + (powerup_PCI_present) ? 1 : 0); + + /* print a bit more if asked politely... */ + if (!(ciaa.pra & 0x40)){ + extern unsigned int bat_addrs[4][3]; + int b; + for (b = 0; b < 4; ++b) { + printk ("APUS: BAT%d ", b); + printk ("%08x-%08x -> %08x\n", + bat_addrs[b][0], + bat_addrs[b][1], + bat_addrs[b][2]); + } + } + + } + + printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", + freq/1000000, freq%1000000); + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); + + __bus_speed = bus_speed; + __speed_test_failed = speed_test_failed; +#endif +} + +void arch_gettod(int *year, int *mon, int *day, int *hour, + int *min, int *sec) +{ +#ifdef CONFIG_APUS + if (mach_gettod) + mach_gettod(year, mon, day, hour, min, sec); + else + *year = *mon = *day = *hour = *min = *sec = 0; +#endif +} + +/* for "kbd-reset" cmdline param */ +__init +void kbd_reset_setup(char *str, int *ints) +{ +} + +/*********************************************************** FLOPPY */ +#if defined(CONFIG_AMIGA_FLOPPY) +__init +void floppy_setup(char *str, int *ints) +{ + if (mach_floppy_setup) + mach_floppy_setup (str, ints); +} +#endif + +/*********************************************************** MEMORY */ +#define KMAP_MAX 32 +unsigned long kmap_chunks[KMAP_MAX*3]; +int kmap_chunk_count = 0; + +/* From pgtable.h */ +static __inline__ pte_t *my_find_pte(struct mm_struct *mm,unsigned long va) +{ + pgd_t *dir = 0; + pmd_t *pmd = 0; + pte_t *pte = 0; + + va &= PAGE_MASK; + + dir = pgd_offset( mm, va ); + if (dir) + { + pmd = pmd_offset(dir, va & PAGE_MASK); + if (pmd && pmd_present(*pmd)) + { + pte = pte_offset(pmd, va); + } + } + return pte; +} + + +/* Again simulating an m68k/mm/kmap.c function. */ +void kernel_set_cachemode( unsigned long address, unsigned long size, + unsigned int cmode ) +{ + unsigned long mask, flags; + + switch (cmode) + { + case IOMAP_FULL_CACHING: + mask = ~(_PAGE_NO_CACHE | _PAGE_GUARDED); + flags = 0; + break; + case IOMAP_NOCACHE_SER: + mask = ~0; + flags = (_PAGE_NO_CACHE | _PAGE_GUARDED); + break; + default: + panic ("kernel_set_cachemode() doesn't support mode %d\n", + cmode); + break; + } + + size /= PAGE_SIZE; + address &= PAGE_MASK; + while (size--) + { + pte_t *pte; + + pte = my_find_pte(&init_mm, address); + if ( !pte ) + { + printk("pte NULL in kernel_set_cachemode()\n"); + return; + } + + pte_val (*pte) &= mask; + pte_val (*pte) |= flags; + flush_tlb_page(find_vma(&init_mm,address),address); + + address += PAGE_SIZE; + } +} + +unsigned long mm_ptov (unsigned long paddr) +{ + unsigned long ret; + if (paddr < 16*1024*1024) + ret = ZTWO_VADDR(paddr); + else { + int i; + + for (i = 0; i < kmap_chunk_count;){ + unsigned long phys = kmap_chunks[i++]; + unsigned long size = kmap_chunks[i++]; + unsigned long virt = kmap_chunks[i++]; + if (paddr >= phys + && paddr < (phys + size)){ + ret = virt + paddr - phys; + goto exit; + } + } + + ret = (unsigned long) __va(paddr); + } +exit: +#ifdef DEBUGPV + printk ("PTOV(%lx)=%lx\n", paddr, ret); +#endif + return ret; +} + +int mm_end_of_chunk (unsigned long addr, int len) +{ + if (memory[0].addr + memory[0].size == addr + len) + return 1; + return 0; +} + +/*********************************************************** CACHE */ + +#define L1_CACHE_BYTES 32 +#define MAX_CACHE_SIZE 8192 +void cache_push(__u32 addr, int length) +{ + addr = mm_ptov(addr); + + if (MAX_CACHE_SIZE < length) + length = MAX_CACHE_SIZE; + + while(length > 0){ + __asm ("dcbf 0,%0\n\t" + : : "r" (addr)); + addr += L1_CACHE_BYTES; + length -= L1_CACHE_BYTES; + } + /* Also flush trailing block */ + __asm ("dcbf 0,%0\n\t" + "sync \n\t" + : : "r" (addr)); +} + +void cache_clear(__u32 addr, int length) +{ + if (MAX_CACHE_SIZE < length) + length = MAX_CACHE_SIZE; + + addr = mm_ptov(addr); + + __asm ("dcbf 0,%0\n\t" + "sync \n\t" + "icbi 0,%0 \n\t" + "isync \n\t" + : : "r" (addr)); + + addr += L1_CACHE_BYTES; + length -= L1_CACHE_BYTES; + + while(length > 0){ + __asm ("dcbf 0,%0\n\t" + "sync \n\t" + "icbi 0,%0 \n\t" + "isync \n\t" + : : "r" (addr)); + addr += L1_CACHE_BYTES; + length -= L1_CACHE_BYTES; + } + + __asm ("dcbf 0,%0\n\t" + "sync \n\t" + "icbi 0,%0 \n\t" + "isync \n\t" + : : "r" (addr)); +} + +/****************************************************** from setup.c */ +void +apus_restart(char *cmd) +{ + local_irq_disable(); + + APUS_WRITE(APUS_REG_LOCK, + REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK2); + APUS_WRITE(APUS_REG_LOCK, + REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK3); + APUS_WRITE(APUS_REG_LOCK, + REGLOCK_BLACKMAGICK2|REGLOCK_BLACKMAGICK3); + APUS_WRITE(APUS_REG_SHADOW, REGSHADOW_SELFRESET); + APUS_WRITE(APUS_REG_RESET, REGRESET_AMIGARESET); + for(;;); +} + +void +apus_power_off(void) +{ + for (;;); +} + +void +apus_halt(void) +{ + apus_restart(NULL); +} + +/****************************************************** IRQ stuff */ + +static unsigned char last_ipl[8]; + +int apus_get_irq(struct pt_regs* regs) +{ + unsigned char ipl_emu, mask; + unsigned int level; + + APUS_READ(APUS_IPL_EMU, ipl_emu); + level = (ipl_emu >> 3) & IPLEMU_IPLMASK; + mask = IPLEMU_SETRESET|IPLEMU_DISABLEINT|level; + level ^= 7; + + /* Save previous IPL value */ + if (last_ipl[level]) + return -2; + last_ipl[level] = ipl_emu; + + /* Set to current IPL value */ + APUS_WRITE(APUS_IPL_EMU, mask); + APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT|level); + + +#ifdef __INTERRUPT_DEBUG + printk("<%d:%d>", level, ~ipl_emu & IPLEMU_IPLMASK); +#endif + return level + IRQ_AMIGA_AUTO; +} + +void apus_end_irq(unsigned int irq) +{ + unsigned char ipl_emu; + unsigned int level = irq - IRQ_AMIGA_AUTO; +#ifdef __INTERRUPT_DEBUG + printk("{%d}", ~last_ipl[level] & IPLEMU_IPLMASK); +#endif + /* Restore IPL to the previous value */ + ipl_emu = last_ipl[level] & IPLEMU_IPLMASK; + APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET|IPLEMU_DISABLEINT|ipl_emu); + last_ipl[level] = 0; + ipl_emu ^= 7; + APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT|ipl_emu); +} + +/****************************************************** debugging */ + +/* some serial hardware definitions */ +#define SDR_OVRUN (1<<15) +#define SDR_RBF (1<<14) +#define SDR_TBE (1<<13) +#define SDR_TSRE (1<<12) + +#define AC_SETCLR (1<<15) +#define AC_UARTBRK (1<<11) + +#define SER_DTR (1<<7) +#define SER_RTS (1<<6) +#define SER_DCD (1<<5) +#define SER_CTS (1<<4) +#define SER_DSR (1<<3) + +static __inline__ void ser_RTSon(void) +{ + ciab.pra &= ~SER_RTS; /* active low */ +} + +int __debug_ser_out( unsigned char c ) +{ + custom.serdat = c | 0x100; + mb(); + while (!(custom.serdatr & 0x2000)) + barrier(); + return 1; +} + +unsigned char __debug_ser_in( void ) +{ + unsigned char c; + + /* XXX: is that ok?? derived from amiga_ser.c... */ + while( !(custom.intreqr & IF_RBF) ) + barrier(); + c = custom.serdatr; + /* clear the interrupt, so that another character can be read */ + custom.intreq = IF_RBF; + return c; +} + +int __debug_serinit( void ) +{ + unsigned long flags; + + local_irq_save(flags); + + /* turn off Rx and Tx interrupts */ + custom.intena = IF_RBF | IF_TBE; + + /* clear any pending interrupt */ + custom.intreq = IF_RBF | IF_TBE; + + local_irq_restore(flags); + + /* + * set the appropriate directions for the modem control flags, + * and clear RTS and DTR + */ + ciab.ddra |= (SER_DTR | SER_RTS); /* outputs */ + ciab.ddra &= ~(SER_DCD | SER_CTS | SER_DSR); /* inputs */ + +#ifdef CONFIG_KGDB + /* turn Rx interrupts on for GDB */ + custom.intena = IF_SETCLR | IF_RBF; + ser_RTSon(); +#endif + + return 0; +} + +void __debug_print_hex(unsigned long x) +{ + int i; + char hexchars[] = "0123456789ABCDEF"; + + for (i = 0; i < 8; i++) { + __debug_ser_out(hexchars[(x >> 28) & 15]); + x <<= 4; + } + __debug_ser_out('\n'); + __debug_ser_out('\r'); +} + +void __debug_print_string(char* s) +{ + unsigned char c; + while((c = *s++)) + __debug_ser_out(c); + __debug_ser_out('\n'); + __debug_ser_out('\r'); +} + +static void apus_progress(char *s, unsigned short value) +{ + __debug_print_string(s); +} + +/****************************************************** init */ + +/* The number of spurious interrupts */ +volatile unsigned int num_spurious; + +extern struct irqaction amiga_sys_irqaction[AUTO_IRQS]; + + +extern void amiga_enable_irq(unsigned int irq); +extern void amiga_disable_irq(unsigned int irq); + +struct hw_interrupt_type amiga_sys_irqctrl = { + .typename = "Amiga IPL", + .end = apus_end_irq, +}; + +struct hw_interrupt_type amiga_irqctrl = { + .typename = "Amiga ", + .enable = amiga_enable_irq, + .disable = amiga_disable_irq, +}; + +#define HARDWARE_MAPPED_SIZE (512*1024) +unsigned long __init apus_find_end_of_memory(void) +{ + int shadow = 0; + unsigned long total; + + /* The memory size reported by ADOS excludes the 512KB + reserved for PPC exception registers and possibly 512KB + containing a shadow of the ADOS ROM. */ + { + unsigned long size = memory[0].size; + + /* If 2MB aligned, size was probably user + specified. We can't tell anything about shadowing + in this case so skip shadow assignment. */ + if (0 != (size & 0x1fffff)){ + /* Align to 512KB to ensure correct handling + of both memfile and system specified + sizes. */ + size = ((size+0x0007ffff) & 0xfff80000); + /* If memory is 1MB aligned, assume + shadowing. */ + shadow = !(size & 0x80000); + } + + /* Add the chunk that ADOS does not see. by aligning + the size to the nearest 2MB limit upwards. */ + memory[0].size = ((size+0x001fffff) & 0xffe00000); + } + + ppc_memstart = memory[0].addr; + ppc_memoffset = PAGE_OFFSET - PPC_MEMSTART; + total = memory[0].size; + + /* Remove the memory chunks that are controlled by special + Phase5 hardware. */ + + /* Remove the upper 512KB if it contains a shadow of + the ADOS ROM. FIXME: It might be possible to + disable this shadow HW. Check the booter + (ppc_boot.c) */ + if (shadow) + total -= HARDWARE_MAPPED_SIZE; + + /* Remove the upper 512KB where the PPC exception + vectors are mapped. */ + total -= HARDWARE_MAPPED_SIZE; + + /* Linux/APUS only handles one block of memory -- the one on + the PowerUP board. Other system memory is horrible slow in + comparison. The user can use other memory for swapping + using the z2ram device. */ + return total; +} + +static void __init +apus_map_io(void) +{ + /* Map PPC exception vectors. */ + io_block_mapping(0xfff00000, 0xfff00000, 0x00020000, _PAGE_KERNEL); + /* Map chip and ZorroII memory */ + io_block_mapping(zTwoBase, 0x00000000, 0x01000000, _PAGE_IO); +} + +__init +void apus_init_IRQ(void) +{ + struct irqaction *action; + int i; + +#ifdef CONFIG_PCI + apus_setup_pci_ptrs(); +#endif + + for ( i = 0 ; i < AMI_IRQS; i++ ) { + irq_desc[i].status = IRQ_LEVEL; + if (i < IRQ_AMIGA_AUTO) { + irq_desc[i].handler = &amiga_irqctrl; + } else { + irq_desc[i].handler = &amiga_sys_irqctrl; + action = &amiga_sys_irqaction[i-IRQ_AMIGA_AUTO]; + if (action->name) + setup_irq(i, action); + } + } + + amiga_init_IRQ(); + +} + +__init +void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + extern int parse_bootinfo(const struct bi_record *); + extern char _end[]; + + /* Parse bootinfo. The bootinfo is located right after + the kernel bss */ + parse_bootinfo((const struct bi_record *)&_end); +#ifdef CONFIG_BLK_DEV_INITRD + /* Take care of initrd if we have one. Use data from + bootinfo to avoid the need to initialize PPC + registers when kernel is booted via a PPC reset. */ + if ( ramdisk.addr ) { + initrd_start = (unsigned long) __va(ramdisk.addr); + initrd_end = (unsigned long) + __va(ramdisk.size + ramdisk.addr); + } +#endif /* CONFIG_BLK_DEV_INITRD */ + + ISA_DMA_THRESHOLD = 0x00ffffff; + + ppc_md.setup_arch = apus_setup_arch; + ppc_md.show_cpuinfo = apus_show_cpuinfo; + ppc_md.init_IRQ = apus_init_IRQ; + ppc_md.get_irq = apus_get_irq; + +#ifdef CONFIG_HEARTBEAT + ppc_md.heartbeat = apus_heartbeat; + ppc_md.heartbeat_count = 1; +#endif +#ifdef APUS_DEBUG + __debug_serinit(); + ppc_md.progress = apus_progress; +#endif + ppc_md.init = NULL; + + ppc_md.restart = apus_restart; + ppc_md.power_off = apus_power_off; + ppc_md.halt = apus_halt; + + ppc_md.time_init = NULL; + ppc_md.set_rtc_time = apus_set_rtc_time; + ppc_md.get_rtc_time = apus_get_rtc_time; + ppc_md.calibrate_decr = apus_calibrate_decr; + + ppc_md.find_end_of_memory = apus_find_end_of_memory; + ppc_md.setup_io_mappings = apus_map_io; +} diff --git a/arch/ppc/platforms/bseip.h b/arch/ppc/platforms/bseip.h new file mode 100644 index 00000000000..691f4a52b0a --- /dev/null +++ b/arch/ppc/platforms/bseip.h @@ -0,0 +1,38 @@ +/* + * A collection of structures, addresses, and values associated with + * the Bright Star Engineering ip-Engine board. Copied from the MBX stuff. + * + * Copyright (c) 1998 Dan Malek (dmalek@jlc.net) + */ +#ifndef __MACH_BSEIP_DEFS +#define __MACH_BSEIP_DEFS + +#ifndef __ASSEMBLY__ +/* A Board Information structure that is given to a program when + * prom starts it up. + */ +typedef struct bd_info { + unsigned int bi_memstart; /* Memory start address */ + unsigned int bi_memsize; /* Memory (end) size in bytes */ + unsigned int bi_intfreq; /* Internal Freq, in Hz */ + unsigned int bi_busfreq; /* Bus Freq, in Hz */ + unsigned char bi_enetaddr[6]; + unsigned int bi_baudrate; +} bd_t; + +extern bd_t m8xx_board_info; + +/* Memory map is configured by the PROM startup. + * All we need to get started is the IMMR. + */ +#define IMAP_ADDR ((uint)0xff000000) +#define IMAP_SIZE ((uint)(64 * 1024)) +#define PCMCIA_MEM_ADDR ((uint)0x04000000) +#define PCMCIA_MEM_SIZE ((uint)(64 * 1024)) +#endif /* !__ASSEMBLY__ */ + +/* We don't use the 8259. +*/ +#define NR_8259_INTS 0 + +#endif diff --git a/arch/ppc/platforms/ccm.h b/arch/ppc/platforms/ccm.h new file mode 100644 index 00000000000..edb87b57383 --- /dev/null +++ b/arch/ppc/platforms/ccm.h @@ -0,0 +1,28 @@ +/* + * Siemens Card Controller Module specific definitions + * + * Copyright (C) 2001-2002 Wolfgang Denk (wd@denx.de) + */ + +#ifndef __MACH_CCM_H +#define __MACH_CCM_H + +#include <linux/config.h> + +#include <asm/ppcboot.h> + +#define CCM_IMMR_BASE 0xF0000000 /* phys. addr of IMMR */ +#define CCM_IMAP_SIZE (64 * 1024) /* size of mapped area */ + +#define IMAP_ADDR CCM_IMMR_BASE /* physical base address of IMMR area */ +#define IMAP_SIZE CCM_IMAP_SIZE /* mapped size of IMMR area */ + +#define FEC_INTERRUPT 13 /* = SIU_LEVEL6 */ +#define DEC_INTERRUPT 11 /* = SIU_LEVEL5 */ +#define CPM_INTERRUPT 9 /* = SIU_LEVEL4 */ + +/* We don't use the 8259. +*/ +#define NR_8259_INTS 0 + +#endif /* __MACH_CCM_H */ diff --git a/arch/ppc/platforms/chestnut.c b/arch/ppc/platforms/chestnut.c new file mode 100644 index 00000000000..7786818bd9d --- /dev/null +++ b/arch/ppc/platforms/chestnut.c @@ -0,0 +1,580 @@ +/* + * arch/ppc/platforms/chestnut.c + * + * Board setup routines for IBM Chestnut + * + * Author: <source@mvista.com> + * + * <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. + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/kdev_t.h> +#include <linux/major.h> +#include <linux/blkdev.h> +#include <linux/console.h> +#include <linux/root_dev.h> +#include <linux/initrd.h> +#include <linux/delay.h> +#include <linux/seq_file.h> +#include <linux/ide.h> +#include <linux/serial.h> +#include <linux/serial_core.h> +#include <linux/mtd/physmap.h> +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/time.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <linux/irq.h> +#include <asm/hw_irq.h> +#include <asm/machdep.h> +#include <asm/kgdb.h> +#include <asm/bootinfo.h> +#include <asm/mv64x60.h> +#include <platforms/chestnut.h> + +static void __iomem *sram_base; /* Virtual addr of Internal SRAM */ +static void __iomem *cpld_base; /* Virtual addr of CPLD Regs */ + +static mv64x60_handle_t bh; + +extern void gen550_progress(char *, unsigned short); +extern void gen550_init(int, struct uart_port *); +extern void mv64360_pcibios_fixup(mv64x60_handle_t *bh); + +#define BIT(x) (1<<x) +#define CHESTNUT_PRESERVE_MASK (BIT(MV64x60_CPU2DEV_0_WIN) | \ + BIT(MV64x60_CPU2DEV_1_WIN) | \ + BIT(MV64x60_CPU2DEV_2_WIN) | \ + BIT(MV64x60_CPU2DEV_3_WIN) | \ + BIT(MV64x60_CPU2BOOT_WIN)) +/************************************************************************** + * FUNCTION: chestnut_calibrate_decr + * + * DESCRIPTION: initialize decrementer interrupt frequency (used as system + * timer) + * + ****/ +static void __init +chestnut_calibrate_decr(void) +{ + ulong freq; + + freq = CHESTNUT_BUS_SPEED / 4; + + printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", + freq/1000000, freq%1000000); + + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); +} + +static int +chestnut_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "vendor\t\t: IBM\n"); + seq_printf(m, "machine\t\t: 750FX/GX Eval Board (Chestnut/Buckeye)\n"); + + return 0; +} + +/************************************************************************** + * FUNCTION: chestnut_find_end_of_memory + * + * DESCRIPTION: ppc_md memory size callback + * + ****/ +unsigned long __init +chestnut_find_end_of_memory(void) +{ + static int mem_size = 0; + + if (mem_size == 0) { + mem_size = mv64x60_get_mem_size(CONFIG_MV64X60_NEW_BASE, + MV64x60_TYPE_MV64460); + } + return mem_size; +} + +#if defined(CONFIG_SERIAL_8250) +static void __init +chestnut_early_serial_map(void) +{ + struct uart_port port; + + /* Setup serial port access */ + memset(&port, 0, sizeof(port)); + port.uartclk = BASE_BAUD * 16; + port.irq = UART0_INT; + port.flags = STD_COM_FLAGS | UPF_IOREMAP; + port.iotype = SERIAL_IO_MEM; + port.mapbase = CHESTNUT_UART0_IO_BASE; + port.regshift = 0; + + if (early_serial_setup(&port) != 0) + printk("Early serial init of port 0 failed\n"); + + /* Assume early_serial_setup() doesn't modify serial_req */ + port.line = 1; + port.irq = UART1_INT; + port.mapbase = CHESTNUT_UART1_IO_BASE; + + if (early_serial_setup(&port) != 0) + printk("Early serial init of port 1 failed\n"); +} +#endif + +/************************************************************************** + * FUNCTION: chestnut_map_irq + * + * DESCRIPTION: 0 return since PCI IRQs not needed + * + ****/ +static int __init +chestnut_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = { + {CHESTNUT_PCI_SLOT0_IRQ, CHESTNUT_PCI_SLOT0_IRQ, + CHESTNUT_PCI_SLOT0_IRQ, CHESTNUT_PCI_SLOT0_IRQ}, + {CHESTNUT_PCI_SLOT1_IRQ, CHESTNUT_PCI_SLOT1_IRQ, + CHESTNUT_PCI_SLOT1_IRQ, CHESTNUT_PCI_SLOT1_IRQ}, + {CHESTNUT_PCI_SLOT2_IRQ, CHESTNUT_PCI_SLOT2_IRQ, + CHESTNUT_PCI_SLOT2_IRQ, CHESTNUT_PCI_SLOT2_IRQ}, + {CHESTNUT_PCI_SLOT3_IRQ, CHESTNUT_PCI_SLOT3_IRQ, + CHESTNUT_PCI_SLOT3_IRQ, CHESTNUT_PCI_SLOT3_IRQ}, + }; + const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4; + + return PCI_IRQ_TABLE_LOOKUP; +} + + +/************************************************************************** + * FUNCTION: chestnut_setup_bridge + * + * DESCRIPTION: initalize board-specific settings on the MV64360 + * + ****/ +static void __init +chestnut_setup_bridge(void) +{ + struct mv64x60_setup_info si; + int i; + + if ( ppc_md.progress ) + ppc_md.progress("chestnut_setup_bridge: enter", 0); + + memset(&si, 0, sizeof(si)); + + si.phys_reg_base = CONFIG_MV64X60_NEW_BASE; + + /* setup only PCI bus 0 (bus 1 not used) */ + si.pci_0.enable_bus = 1; + si.pci_0.pci_io.cpu_base = CHESTNUT_PCI0_IO_PROC_ADDR; + si.pci_0.pci_io.pci_base_hi = 0; + si.pci_0.pci_io.pci_base_lo = CHESTNUT_PCI0_IO_PCI_ADDR; + si.pci_0.pci_io.size = CHESTNUT_PCI0_IO_SIZE; + si.pci_0.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE; /* no swapping */ + si.pci_0.pci_mem[0].cpu_base = CHESTNUT_PCI0_MEM_PROC_ADDR; + si.pci_0.pci_mem[0].pci_base_hi = CHESTNUT_PCI0_MEM_PCI_HI_ADDR; + si.pci_0.pci_mem[0].pci_base_lo = CHESTNUT_PCI0_MEM_PCI_LO_ADDR; + si.pci_0.pci_mem[0].size = CHESTNUT_PCI0_MEM_SIZE; + si.pci_0.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE; /* no swapping */ + si.pci_0.pci_cmd_bits = 0; + si.pci_0.latency_timer = 0x80; + + for (i=0; i<MV64x60_CPU2MEM_WINDOWS; i++) { +#if defined(CONFIG_NOT_COHERENT_CACHE) + si.cpu_prot_options[i] = 0; + si.enet_options[i] = MV64360_ENET2MEM_SNOOP_NONE; + si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_NONE; + si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE; + + si.pci_1.acc_cntl_options[i] = + MV64360_PCI_ACC_CNTL_SNOOP_NONE | + MV64360_PCI_ACC_CNTL_SWAP_NONE | + MV64360_PCI_ACC_CNTL_MBURST_128_BYTES | + MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES; +#else + si.cpu_prot_options[i] = 0; + si.enet_options[i] = MV64360_ENET2MEM_SNOOP_NONE; /* errata */ + si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_NONE; /* errata */ + si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE; /* errata */ + + si.pci_1.acc_cntl_options[i] = + MV64360_PCI_ACC_CNTL_SNOOP_WB | + MV64360_PCI_ACC_CNTL_SWAP_NONE | + MV64360_PCI_ACC_CNTL_MBURST_32_BYTES | + MV64360_PCI_ACC_CNTL_RDSIZE_32_BYTES; +#endif + } + + /* Lookup host bridge - on CPU 0 - no SMP support */ + if (mv64x60_init(&bh, &si)) { + printk("\n\nPCI Bridge initialization failed!\n"); + } + + pci_dram_offset = 0; + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = chestnut_map_irq; + ppc_md.pci_exclude_device = mv64x60_pci_exclude_device; + + mv64x60_set_bus(&bh, 0, 0); + bh.hose_a->first_busno = 0; + bh.hose_a->last_busno = 0xff; + bh.hose_a->last_busno = pciauto_bus_scan(bh.hose_a, 0); +} + +void __init +chestnut_setup_peripherals(void) +{ + mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN, + CHESTNUT_BOOT_8BIT_BASE, CHESTNUT_BOOT_8BIT_SIZE, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN); + + mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_0_WIN, + CHESTNUT_32BIT_BASE, CHESTNUT_32BIT_SIZE, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_0_WIN); + + mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN, + CHESTNUT_CPLD_BASE, CHESTNUT_CPLD_SIZE, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_1_WIN); + cpld_base = ioremap(CHESTNUT_CPLD_BASE, CHESTNUT_CPLD_SIZE); + + mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_2_WIN, + CHESTNUT_UART_BASE, CHESTNUT_UART_SIZE, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_2_WIN); + + mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_3_WIN, + CHESTNUT_FRAM_BASE, CHESTNUT_FRAM_SIZE, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_3_WIN); + + mv64x60_set_32bit_window(&bh, MV64x60_CPU2SRAM_WIN, + CHESTNUT_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN); + +#ifdef CONFIG_NOT_COHERENT_CACHE + mv64x60_write(&bh, MV64360_SRAM_CONFIG, 0x001600b0); +#else + mv64x60_write(&bh, MV64360_SRAM_CONFIG, 0x001600b2); +#endif + sram_base = ioremap(CHESTNUT_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE); + memset(sram_base, 0, MV64360_SRAM_SIZE); + + /* + * Configure MPP pins for PCI DMA + * + * PCI Slot GNT pin REQ pin + * 0 MPP16 MPP17 + * 1 MPP18 MPP19 + * 2 MPP20 MPP21 + * 3 MPP22 MPP23 + */ + mv64x60_write(&bh, MV64x60_MPP_CNTL_2, + (0x1 << 0) | /* MPPSel16 PCI0_GNT[0] */ + (0x1 << 4) | /* MPPSel17 PCI0_REQ[0] */ + (0x1 << 8) | /* MPPSel18 PCI0_GNT[1] */ + (0x1 << 12) | /* MPPSel19 PCI0_REQ[1] */ + (0x1 << 16) | /* MPPSel20 PCI0_GNT[2] */ + (0x1 << 20) | /* MPPSel21 PCI0_REQ[2] */ + (0x1 << 24) | /* MPPSel22 PCI0_GNT[3] */ + (0x1 << 28)); /* MPPSel23 PCI0_REQ[3] */ + /* + * Set unused MPP pins for output, as per schematic note + * + * Unused Pins: MPP01, MPP02, MPP04, MPP05, MPP06 + * MPP09, MPP10, MPP13, MPP14, MPP15 + */ + mv64x60_clr_bits(&bh, MV64x60_MPP_CNTL_0, + (0xf << 4) | /* MPPSel01 GPIO[1] */ + (0xf << 8) | /* MPPSel02 GPIO[2] */ + (0xf << 16) | /* MPPSel04 GPIO[4] */ + (0xf << 20) | /* MPPSel05 GPIO[5] */ + (0xf << 24)); /* MPPSel06 GPIO[6] */ + mv64x60_clr_bits(&bh, MV64x60_MPP_CNTL_1, + (0xf << 4) | /* MPPSel09 GPIO[9] */ + (0xf << 8) | /* MPPSel10 GPIO[10] */ + (0xf << 20) | /* MPPSel13 GPIO[13] */ + (0xf << 24) | /* MPPSel14 GPIO[14] */ + (0xf << 28)); /* MPPSel15 GPIO[15] */ + mv64x60_set_bits(&bh, MV64x60_GPP_IO_CNTL, /* Output */ + BIT(1) | BIT(2) | BIT(4) | BIT(5) | BIT(6) | + BIT(9) | BIT(10) | BIT(13) | BIT(14) | BIT(15)); + + /* + * Configure the following MPP pins to indicate a level + * triggered interrupt + * + * MPP24 - Board Reset (just map the MPP & GPP for chestnut_reset) + * MPP25 - UART A (high) + * MPP26 - UART B (high) + * MPP28 - PCI Slot 3 (low) + * MPP29 - PCI Slot 2 (low) + * MPP30 - PCI Slot 1 (low) + * MPP31 - PCI Slot 0 (low) + */ + mv64x60_clr_bits(&bh, MV64x60_MPP_CNTL_3, + BIT(3) | BIT(2) | BIT(1) | BIT(0) | /* MPP 24 */ + BIT(7) | BIT(6) | BIT(5) | BIT(4) | /* MPP 25 */ + BIT(11) | BIT(10) | BIT(9) | BIT(8) | /* MPP 26 */ + BIT(19) | BIT(18) | BIT(17) | BIT(16) | /* MPP 28 */ + BIT(23) | BIT(22) | BIT(21) | BIT(20) | /* MPP 29 */ + BIT(27) | BIT(26) | BIT(25) | BIT(24) | /* MPP 30 */ + BIT(31) | BIT(30) | BIT(29) | BIT(28)); /* MPP 31 */ + + /* + * Define GPP 25 (high), 26 (high), 28 (low), 29 (low), 30 (low), + * 31 (low) interrupt polarity input signal and level triggered + */ + mv64x60_clr_bits(&bh, MV64x60_GPP_LEVEL_CNTL, BIT(25) | BIT(26)); + mv64x60_set_bits(&bh, MV64x60_GPP_LEVEL_CNTL, + BIT(28) | BIT(29) | BIT(30) | BIT(31)); + mv64x60_clr_bits(&bh, MV64x60_GPP_IO_CNTL, + BIT(25) | BIT(26) | BIT(28) | BIT(29) | BIT(30) | + BIT(31)); + + /* Config GPP interrupt controller to respond to level trigger */ + mv64x60_set_bits(&bh, MV64360_COMM_ARBITER_CNTL, BIT(10)); + + /* + * Dismiss and then enable interrupt on GPP interrupt cause for CPU #0 + */ + mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, + ~(BIT(25) | BIT(26) | BIT(28) | BIT(29) | BIT(30) | + BIT(31))); + mv64x60_set_bits(&bh, MV64x60_GPP_INTR_MASK, + BIT(25) | BIT(26) | BIT(28) | BIT(29) | BIT(30) | + BIT(31)); + + /* + * Dismiss and then enable interrupt on CPU #0 high cause register + * BIT27 summarizes GPP interrupts 24-31 + */ + mv64x60_set_bits(&bh, MV64360_IC_CPU0_INTR_MASK_HI, BIT(27)); + + if (ppc_md.progress) + ppc_md.progress("chestnut_setup_bridge: exit", 0); +} + +/************************************************************************** + * FUNCTION: chestnut_setup_arch + * + * DESCRIPTION: ppc_md machine configuration callback + * + ****/ +static void __init +chestnut_setup_arch(void) +{ + if (ppc_md.progress) + ppc_md.progress("chestnut_setup_arch: enter", 0); + + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000 / HZ; + + /* if the time base value is greater than bus freq/4 (the TB and + * decrementer tick rate) + signed integer rollover value, we + * can spend a fair amount of time waiting for the rollover to + * happen. To get around this, initialize the time base register + * to a "safe" value. + */ + set_tb(0, 0); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_SDA2; +#endif + + /* + * Set up the L2CR register. + */ + _set_L2CR(_get_L2CR() | L2CR_L2E); + + chestnut_setup_bridge(); + chestnut_setup_peripherals(); + +#ifdef CONFIG_DUMMY_CONSOLE + conswitchp = &dummy_con; +#endif + +#if defined(CONFIG_SERIAL_8250) + chestnut_early_serial_map(); +#endif + + /* Identify the system */ + printk(KERN_INFO "System Identification: IBM 750FX/GX Eval Board\n"); + printk(KERN_INFO "IBM 750FX/GX port (C) 2004 MontaVista Software, Inc." + " (source@mvista.com)\n"); + + if (ppc_md.progress) + ppc_md.progress("chestnut_setup_arch: exit", 0); +} + +#ifdef CONFIG_MTD_PHYSMAP +static struct mtd_partition ptbl; + +static int __init +chestnut_setup_mtd(void) +{ + memset(&ptbl, 0, sizeof(ptbl)); + + ptbl.name = "User FS"; + ptbl.size = CHESTNUT_32BIT_SIZE; + + physmap_map.size = CHESTNUT_32BIT_SIZE; + physmap_set_partitions(&ptbl, 1); + return 0; +} + +arch_initcall(chestnut_setup_mtd); +#endif + +/************************************************************************** + * FUNCTION: chestnut_restart + * + * DESCRIPTION: ppc_md machine reset callback + * reset the board via the CPLD command register + * + ****/ +static void +chestnut_restart(char *cmd) +{ + volatile ulong i = 10000000; + + local_irq_disable(); + + /* + * Set CPLD Reg 3 bit 0 to 1 to allow MPP signals on reset to work + * + * MPP24 - board reset + */ + writeb(0x1, cpld_base + 3); + + /* GPP pin tied to MPP earlier */ + mv64x60_set_bits(&bh, MV64x60_GPP_VALUE_SET, BIT(24)); + + while (i-- > 0); + panic("restart failed\n"); +} + +static void +chestnut_halt(void) +{ + local_irq_disable(); + for (;;); + /* NOTREACHED */ +} + +static void +chestnut_power_off(void) +{ + chestnut_halt(); + /* NOTREACHED */ +} + +/************************************************************************** + * FUNCTION: chestnut_map_io + * + * DESCRIPTION: configure fixed memory-mapped IO + * + ****/ +static void __init +chestnut_map_io(void) +{ +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) + io_block_mapping(CHESTNUT_UART_BASE, CHESTNUT_UART_BASE, 0x100000, + _PAGE_IO); +#endif +} + +/************************************************************************** + * FUNCTION: chestnut_set_bat + * + * DESCRIPTION: configures a (temporary) bat mapping for early access to + * device I/O + * + ****/ +static __inline__ void +chestnut_set_bat(void) +{ + mb(); + mtspr(SPRN_DBAT3U, 0xf0001ffe); + mtspr(SPRN_DBAT3L, 0xf000002a); + mb(); +} + +/************************************************************************** + * FUNCTION: platform_init + * + * DESCRIPTION: main entry point for configuring board-specific machine + * callbacks + * + ****/ +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + parse_bootinfo(find_bootinfo()); + + /* Copy the kernel command line arguments to a safe place. */ + + if (r6) { + *(char *) (r7 + KERNELBASE) = 0; + strcpy(cmd_line, (char *) (r6 + KERNELBASE)); + } + + isa_mem_base = 0; + + ppc_md.setup_arch = chestnut_setup_arch; + ppc_md.show_cpuinfo = chestnut_show_cpuinfo; + ppc_md.irq_canonicalize = NULL; + ppc_md.init_IRQ = mv64360_init_irq; + ppc_md.get_irq = mv64360_get_irq; + ppc_md.init = NULL; + + ppc_md.find_end_of_memory = chestnut_find_end_of_memory; + ppc_md.setup_io_mappings = chestnut_map_io; + + ppc_md.restart = chestnut_restart; + ppc_md.power_off = chestnut_power_off; + ppc_md.halt = chestnut_halt; + + ppc_md.time_init = NULL; + ppc_md.set_rtc_time = NULL; + ppc_md.get_rtc_time = NULL; + ppc_md.calibrate_decr = chestnut_calibrate_decr; + + ppc_md.nvram_read_val = NULL; + ppc_md.nvram_write_val = NULL; + + ppc_md.heartbeat = NULL; + + bh.p_base = CONFIG_MV64X60_NEW_BASE; + + chestnut_set_bat(); + +#if defined(CONFIG_SERIAL_TEXT_DEBUG) + ppc_md.progress = gen550_progress; +#endif +#if defined(CONFIG_KGDB) + ppc_md.kgdb_map_scc = gen550_kgdb_map_scc; +#endif + + if (ppc_md.progress) + ppc_md.progress("chestnut_init(): exit", 0); +} diff --git a/arch/ppc/platforms/chestnut.h b/arch/ppc/platforms/chestnut.h new file mode 100644 index 00000000000..0400b2be40a --- /dev/null +++ b/arch/ppc/platforms/chestnut.h @@ -0,0 +1,129 @@ +/* + * arch/ppc/platforms/chestnut.h + * + * Definitions for IBM 750FXGX Eval (Chestnut) + * + * Author: <source@mvista.com> + * + * Based on Artesyn Katana code done by Tim Montgomery <timm@artesyncp.com> + * Based on code done by Rabeeh Khoury - rabeeh@galileo.co.il + * Based on code done by Mark A. Greer <mgreer@mvista.com> + * + * <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. + */ + +/* + * This is the CPU physical memory map (windows must be at least 1MB and start + * on a boundary that is a multiple of the window size): + * + * Seems on the IBM 750FXGX Eval board, the MV64460 Registers can be in + * only 2 places per switch U17 0x14000000 or 0xf1000000 easily - chose to + * implement at 0xf1000000 only at this time + * + * 0xfff00000-0xffffffff - 8 Flash + * 0xffe00000-0xffefffff - BOOT SRAM + * 0xffd00000-0xffd00004 - CPLD + * 0xffc00000-0xffc0000f - UART + * 0xffb00000-0xffb07fff - FRAM + * 0xff840000-0xffafffff - *** HOLE *** + * 0xff800000-0xff83ffff - MV64460 Integrated SRAM + * 0xfe000000-0xff8fffff - *** HOLE *** + * 0xfc000000-0xfdffffff - 32bit Flash + * 0xf1010000-0xfbffffff - *** HOLE *** + * 0xf1000000-0xf100ffff - MV64460 Registers + */ + +#ifndef __PPC_PLATFORMS_CHESTNUT_H__ +#define __PPC_PLATFORMS_CHESTNUT_H__ + +#define CHESTNUT_BOOT_8BIT_BASE 0xfff00000 +#define CHESTNUT_BOOT_8BIT_SIZE_ACTUAL (1024*1024) +#define CHESTNUT_BOOT_SRAM_BASE 0xffe00000 +#define CHESTNUT_BOOT_SRAM_SIZE_ACTUAL (1024*1024) +#define CHESTNUT_CPLD_BASE 0xffd00000 +#define CHESTNUT_CPLD_SIZE_ACTUAL 5 +#define CHESTNUT_CPLD_REG3 (CHESTNUT_CPLD_BASE+3) +#define CHESTNUT_UART_BASE 0xffc00000 +#define CHESTNUT_UART_SIZE_ACTUAL 16 +#define CHESTNUT_FRAM_BASE 0xffb00000 +#define CHESTNUT_FRAM_SIZE_ACTUAL (32*1024) +#define CHESTNUT_INTERNAL_SRAM_BASE 0xff800000 +#define CHESTNUT_32BIT_BASE 0xfc000000 +#define CHESTNUT_32BIT_SIZE (32*1024*1024) + +#define CHESTNUT_BOOT_8BIT_SIZE max(MV64360_WINDOW_SIZE_MIN, \ + CHESTNUT_BOOT_8BIT_SIZE_ACTUAL) +#define CHESTNUT_BOOT_SRAM_SIZE max(MV64360_WINDOW_SIZE_MIN, \ + CHESTNUT_BOOT_SRAM_SIZE_ACTUAL) +#define CHESTNUT_CPLD_SIZE max(MV64360_WINDOW_SIZE_MIN, \ + CHESTNUT_CPLD_SIZE_ACTUAL) +#define CHESTNUT_UART_SIZE max(MV64360_WINDOW_SIZE_MIN, \ + CHESTNUT_UART_SIZE_ACTUAL) +#define CHESTNUT_FRAM_SIZE max(MV64360_WINDOW_SIZE_MIN, \ + CHESTNUT_FRAM_SIZE_ACTUAL) + +#define CHESTNUT_BUS_SPEED 200000000 +#define CHESTNUT_PIBS_DATABASE 0xf0000 /* from PIBS src code */ + +#define KATANA_ETH0_PHY_ADDR 12 +#define KATANA_ETH1_PHY_ADDR 11 +#define KATANA_ETH2_PHY_ADDR 4 + +#define CHESTNUT_ETH_TX_QUEUE_SIZE 800 +#define CHESTNUT_ETH_RX_QUEUE_SIZE 400 + +/* + * PCI windows + */ + +#define CHESTNUT_PCI0_MEM_PROC_ADDR 0x80000000 +#define CHESTNUT_PCI0_MEM_PCI_HI_ADDR 0x00000000 +#define CHESTNUT_PCI0_MEM_PCI_LO_ADDR 0x80000000 +#define CHESTNUT_PCI0_MEM_SIZE 0x10000000 +#define CHESTNUT_PCI0_IO_PROC_ADDR 0xa0000000 +#define CHESTNUT_PCI0_IO_PCI_ADDR 0x00000000 +#define CHESTNUT_PCI0_IO_SIZE 0x01000000 + +/* + * Board-specific IRQ info + */ +#define CHESTNUT_PCI_SLOT0_IRQ (64 + 31) +#define CHESTNUT_PCI_SLOT1_IRQ (64 + 30) +#define CHESTNUT_PCI_SLOT2_IRQ (64 + 29) +#define CHESTNUT_PCI_SLOT3_IRQ (64 + 28) + +/* serial port definitions */ +#define CHESTNUT_UART0_IO_BASE (CHESTNUT_UART_BASE + 8) +#define CHESTNUT_UART1_IO_BASE CHESTNUT_UART_BASE + +#define UART0_INT (64 + 25) +#define UART1_INT (64 + 26) + +#ifdef CONFIG_SERIAL_MANY_PORTS +#define RS_TABLE_SIZE 64 +#else +#define RS_TABLE_SIZE 2 +#endif + +/* Rate for the 3.6864 Mhz clock for the onboard serial chip */ +#define BASE_BAUD (3686400 / 16) + +#ifdef CONFIG_SERIAL_DETECT_IRQ +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ) +#else +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST) +#endif + +#define STD_UART_OP(num) \ + { 0, BASE_BAUD, 0, UART##num##_INT, STD_COM_FLAGS, \ + iomem_base: (u8 *)CHESTNUT_UART##num##_IO_BASE, \ + io_type: SERIAL_IO_MEM}, + +#define SERIAL_PORT_DFNS \ + STD_UART_OP(0) \ + STD_UART_OP(1) + +#endif /* __PPC_PLATFORMS_CHESTNUT_H__ */ diff --git a/arch/ppc/platforms/chrp_pci.c b/arch/ppc/platforms/chrp_pci.c new file mode 100644 index 00000000000..5bb6492ecf8 --- /dev/null +++ b/arch/ppc/platforms/chrp_pci.c @@ -0,0 +1,309 @@ +/* + * CHRP pci routines. + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/string.h> +#include <linux/init.h> +#include <linux/ide.h> +#include <linux/bootmem.h> + +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/irq.h> +#include <asm/hydra.h> +#include <asm/prom.h> +#include <asm/gg2.h> +#include <asm/machdep.h> +#include <asm/sections.h> +#include <asm/pci-bridge.h> +#include <asm/open_pic.h> + +/* LongTrail */ +void __iomem *gg2_pci_config_base; + +/* + * The VLSI Golden Gate II has only 512K of PCI configuration space, so we + * limit the bus number to 3 bits + */ + +int __chrp gg2_read_config(struct pci_bus *bus, unsigned int devfn, int off, + int len, u32 *val) +{ + volatile void __iomem *cfg_data; + struct pci_controller *hose = bus->sysdata; + + if (bus->number > 7) + return PCIBIOS_DEVICE_NOT_FOUND; + /* + * Note: the caller has already checked that off is + * suitably aligned and that len is 1, 2 or 4. + */ + cfg_data = hose->cfg_data + ((bus->number<<16) | (devfn<<8) | off); + switch (len) { + case 1: + *val = in_8(cfg_data); + break; + case 2: + *val = in_le16(cfg_data); + break; + default: + *val = in_le32(cfg_data); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +int __chrp gg2_write_config(struct pci_bus *bus, unsigned int devfn, int off, + int len, u32 val) +{ + volatile void __iomem *cfg_data; + struct pci_controller *hose = bus->sysdata; + + if (bus->number > 7) + return PCIBIOS_DEVICE_NOT_FOUND; + /* + * Note: the caller has already checked that off is + * suitably aligned and that len is 1, 2 or 4. + */ + cfg_data = hose->cfg_data + ((bus->number<<16) | (devfn<<8) | off); + switch (len) { + case 1: + out_8(cfg_data, val); + break; + case 2: + out_le16(cfg_data, val); + break; + default: + out_le32(cfg_data, val); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops gg2_pci_ops = +{ + gg2_read_config, + gg2_write_config +}; + +/* + * Access functions for PCI config space using RTAS calls. + */ +int __chrp +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); + unsigned long ret = ~0UL; + int rval; + + rval = call_rtas("read-pci-config", 2, 2, &ret, addr, len); + *val = ret; + return rval? PCIBIOS_DEVICE_NOT_FOUND: PCIBIOS_SUCCESSFUL; +} + +int __chrp +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 = call_rtas("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 +}; + +volatile struct Hydra *Hydra = NULL; + +int __init +hydra_init(void) +{ + struct device_node *np; + + np = find_devices("mac-io"); + if (np == NULL || np->n_addrs == 0) + return 0; + Hydra = ioremap(np->addrs[0].address, np->addrs[0].size); + printk("Hydra Mac I/O at %x\n", np->addrs[0].address); + printk("Hydra Feature_Control was %x", + in_le32(&Hydra->Feature_Control)); + out_le32(&Hydra->Feature_Control, (HYDRA_FC_SCC_CELL_EN | + HYDRA_FC_SCSI_CELL_EN | + HYDRA_FC_SCCA_ENABLE | + HYDRA_FC_SCCB_ENABLE | + HYDRA_FC_ARB_BYPASS | + HYDRA_FC_MPIC_ENABLE | + HYDRA_FC_SLOW_SCC_PCLK | + HYDRA_FC_MPIC_IS_MASTER)); + printk(", now %x\n", in_le32(&Hydra->Feature_Control)); + return 1; +} + +void __init +chrp_pcibios_fixup(void) +{ + struct pci_dev *dev = NULL; + struct device_node *np; + + /* PCI interrupts are controlled by the OpenPIC */ + for_each_pci_dev(dev) { + np = pci_device_to_OF_node(dev); + if ((np != 0) && (np->n_intrs > 0) && (np->intrs[0].line != 0)) + dev->irq = np->intrs[0].line; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + } +} + +#define PRG_CL_RESET_VALID 0x00010000 + +static void __init +setup_python(struct pci_controller *hose, struct device_node *dev) +{ + u32 *reg, val; + unsigned long addr = dev->addrs[0].address; + + setup_indirect_pci(hose, addr + 0xf8000, addr + 0xf8010); + + /* Clear the magic go-slow bit */ + reg = (u32 *) ioremap(dev->addrs[0].address + 0xf6000, 0x40); + val = in_be32(®[12]); + if (val & PRG_CL_RESET_VALID) { + out_be32(®[12], val & ~PRG_CL_RESET_VALID); + in_be32(®[12]); + } + iounmap(reg); +} + +/* Marvell Discovery II based Pegasos 2 */ +static void __init setup_peg2(struct pci_controller *hose, struct device_node *dev) +{ + struct device_node *root = find_path_device("/"); + struct device_node *rtas; + + rtas = of_find_node_by_name (root, "rtas"); + if (rtas) { + hose->ops = &rtas_pci_ops; + } else { + printk ("RTAS supporting Pegasos OF not found, please upgrade" + " your firmware\n"); + } + pci_assign_all_busses = 1; +} + +void __init +chrp_find_bridges(void) +{ + struct device_node *dev; + int *bus_range; + int len, index = -1; + struct pci_controller *hose; + unsigned int *dma; + char *model, *machine; + int is_longtrail = 0, is_mot = 0, is_pegasos = 0; + struct device_node *root = find_path_device("/"); + + /* + * The PCI host bridge nodes on some machines don't have + * properties to adequately identify them, so we have to + * look at what sort of machine this is as well. + */ + machine = get_property(root, "model", NULL); + if (machine != NULL) { + is_longtrail = strncmp(machine, "IBM,LongTrail", 13) == 0; + is_mot = strncmp(machine, "MOT", 3) == 0; + if (strncmp(machine, "Pegasos2", 8) == 0) + is_pegasos = 2; + else if (strncmp(machine, "Pegasos", 7) == 0) + is_pegasos = 1; + } + for (dev = root->child; dev != NULL; dev = dev->sibling) { + if (dev->type == NULL || strcmp(dev->type, "pci") != 0) + continue; + ++index; + /* The GG2 bridge on the LongTrail doesn't have an address */ + if (dev->n_addrs < 1 && !is_longtrail) { + printk(KERN_WARNING "Can't use %s: no address\n", + dev->full_name); + continue; + } + bus_range = (int *) get_property(dev, "bus-range", &len); + if (bus_range == NULL || len < 2 * sizeof(int)) { + printk(KERN_WARNING "Can't get bus-range for %s\n", + dev->full_name); + continue; + } + if (bus_range[1] == bus_range[0]) + printk(KERN_INFO "PCI bus %d", bus_range[0]); + else + printk(KERN_INFO "PCI buses %d..%d", + bus_range[0], bus_range[1]); + printk(" controlled by %s", dev->type); + if (dev->n_addrs > 0) + printk(" at %x", dev->addrs[0].address); + printk("\n"); + + hose = pcibios_alloc_controller(); + if (!hose) { + printk("Can't allocate PCI controller structure for %s\n", + dev->full_name); + continue; + } + hose->arch_data = dev; + hose->first_busno = bus_range[0]; + hose->last_busno = bus_range[1]; + + model = get_property(dev, "model", NULL); + if (model == NULL) + model = "<none>"; + if (device_is_compatible(dev, "IBM,python")) { + setup_python(hose, dev); + } else if (is_mot + || strncmp(model, "Motorola, Grackle", 17) == 0) { + setup_grackle(hose); + } else if (is_longtrail) { + void __iomem *p = ioremap(GG2_PCI_CONFIG_BASE, 0x80000); + hose->ops = &gg2_pci_ops; + hose->cfg_data = p; + gg2_pci_config_base = p; + } else if (is_pegasos == 1) { + setup_indirect_pci(hose, 0xfec00cf8, 0xfee00cfc); + } else if (is_pegasos == 2) { + setup_peg2(hose, dev); + } else { + printk("No methods for %s (model %s), using RTAS\n", + dev->full_name, model); + hose->ops = &rtas_pci_ops; + } + + pci_process_bridge_OF_ranges(hose, dev, index == 0); + + /* check the first bridge for a property that we can + use to set pci_dram_offset */ + dma = (unsigned int *) + get_property(dev, "ibm,dma-ranges", &len); + if (index == 0 && dma != NULL && len >= 6 * sizeof(*dma)) { + pci_dram_offset = dma[2] - dma[3]; + printk("pci_dram_offset = %lx\n", pci_dram_offset); + } + } + + /* Do not fixup interrupts from OF tree on pegasos */ + if (is_pegasos == 0) + ppc_md.pcibios_fixup = chrp_pcibios_fixup; +} diff --git a/arch/ppc/platforms/chrp_pegasos_eth.c b/arch/ppc/platforms/chrp_pegasos_eth.c new file mode 100644 index 00000000000..cad5bfa153b --- /dev/null +++ b/arch/ppc/platforms/chrp_pegasos_eth.c @@ -0,0 +1,101 @@ +/* + * arch/ppc/platforms/chrp_pegasos_eth.c + * + * Copyright (C) 2005 Sven Luther <sl@bplan-gmbh.de> + * Thanks to : + * Dale Farnsworth <dale@farnsworth.org> + * Mark A. Greer <mgreer@mvista.com> + * Nicolas DET <nd@bplan-gmbh.de> + * Benjamin Herrenschmidt <benh@kernel.crashing.org> + * And anyone else who helped me on this. + */ + +#include <linux/types.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/device.h> +#include <linux/mv643xx.h> +#include <linux/pci.h> + +/* Pegasos 2 specific Marvell MV 64361 gigabit ethernet port setup */ +static struct resource mv643xx_eth_shared_resources[] = { + [0] = { + .name = "ethernet shared base", + .start = 0xf1000000 + MV643XX_ETH_SHARED_REGS, + .end = 0xf1000000 + MV643XX_ETH_SHARED_REGS + + MV643XX_ETH_SHARED_REGS_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device mv643xx_eth_shared_device = { + .name = MV643XX_ETH_SHARED_NAME, + .id = 0, + .num_resources = ARRAY_SIZE(mv643xx_eth_shared_resources), + .resource = mv643xx_eth_shared_resources, +}; + +static struct resource mv643xx_eth0_resources[] = { + [0] = { + .name = "eth0 irq", + .start = 9, + .end = 9, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct mv643xx_eth_platform_data eth0_pd; + +static struct platform_device eth0_device = { + .name = MV643XX_ETH_NAME, + .id = 0, + .num_resources = ARRAY_SIZE(mv643xx_eth0_resources), + .resource = mv643xx_eth0_resources, + .dev = { + .platform_data = ð0_pd, + }, +}; + +static struct resource mv643xx_eth1_resources[] = { + [0] = { + .name = "eth1 irq", + .start = 9, + .end = 9, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct mv643xx_eth_platform_data eth1_pd; + +static struct platform_device eth1_device = { + .name = MV643XX_ETH_NAME, + .id = 1, + .num_resources = ARRAY_SIZE(mv643xx_eth1_resources), + .resource = mv643xx_eth1_resources, + .dev = { + .platform_data = ð1_pd, + }, +}; + +static struct platform_device *mv643xx_eth_pd_devs[] __initdata = { + &mv643xx_eth_shared_device, + ð0_device, + ð1_device, +}; + + +int +mv643xx_eth_add_pds(void) +{ + int ret = 0; + static struct pci_device_id pci_marvell_mv64360[] = { + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_MV64360) }, + { } + }; + + if (pci_dev_present(pci_marvell_mv64360)) { + ret = platform_add_devices(mv643xx_eth_pd_devs, ARRAY_SIZE(mv643xx_eth_pd_devs)); + } + return ret; +} +device_initcall(mv643xx_eth_add_pds); diff --git a/arch/ppc/platforms/chrp_setup.c b/arch/ppc/platforms/chrp_setup.c new file mode 100644 index 00000000000..f23c4f32076 --- /dev/null +++ b/arch/ppc/platforms/chrp_setup.c @@ -0,0 +1,615 @@ +/* + * arch/ppc/platforms/setup.c + * + * Copyright (C) 1995 Linus Torvalds + * Adapted from 'alpha' version by Gary Thomas + * Modified by Cort Dougan (cort@cs.nmt.edu) + */ + +/* + * bootup setup stuff.. + */ + +#include <linux/config.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/stddef.h> +#include <linux/unistd.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/user.h> +#include <linux/a.out.h> +#include <linux/tty.h> +#include <linux/major.h> +#include <linux/interrupt.h> +#include <linux/reboot.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/version.h> +#include <linux/adb.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/ide.h> +#include <linux/irq.h> +#include <linux/console.h> +#include <linux/seq_file.h> +#include <linux/root_dev.h> +#include <linux/initrd.h> +#include <linux/module.h> + +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/prom.h> +#include <asm/gg2.h> +#include <asm/pci-bridge.h> +#include <asm/dma.h> +#include <asm/machdep.h> +#include <asm/irq.h> +#include <asm/hydra.h> +#include <asm/sections.h> +#include <asm/time.h> +#include <asm/btext.h> +#include <asm/i8259.h> +#include <asm/open_pic.h> +#include <asm/xmon.h> + +unsigned long chrp_get_rtc_time(void); +int chrp_set_rtc_time(unsigned long nowtime); +void chrp_calibrate_decr(void); +long chrp_time_init(void); + +void chrp_find_bridges(void); +void chrp_event_scan(void); +void rtas_display_progress(char *, unsigned short); +void rtas_indicator_progress(char *, unsigned short); +void btext_progress(char *, unsigned short); + +extern unsigned long pmac_find_end_of_memory(void); +extern int of_show_percpuinfo(struct seq_file *, int); + +int _chrp_type; +EXPORT_SYMBOL(_chrp_type); + +/* + * XXX this should be in xmon.h, but putting it there means xmon.h + * has to include <linux/interrupt.h> (to get irqreturn_t), which + * causes all sorts of problems. -- paulus + */ +extern irqreturn_t xmon_irq(int, void *, struct pt_regs *); + +extern dev_t boot_dev; + +extern PTE *Hash, *Hash_end; +extern unsigned long Hash_size, Hash_mask; +extern int probingmem; +extern unsigned long loops_per_jiffy; +static int max_width; + +#ifdef CONFIG_SMP +extern struct smp_ops_t chrp_smp_ops; +#endif + +static const char *gg2_memtypes[4] = { + "FPM", "SDRAM", "EDO", "BEDO" +}; +static const char *gg2_cachesizes[4] = { + "256 KB", "512 KB", "1 MB", "Reserved" +}; +static const char *gg2_cachetypes[4] = { + "Asynchronous", "Reserved", "Flow-Through Synchronous", + "Pipelined Synchronous" +}; +static const char *gg2_cachemodes[4] = { + "Disabled", "Write-Through", "Copy-Back", "Transparent Mode" +}; + +int __chrp +chrp_show_cpuinfo(struct seq_file *m) +{ + int i, sdramen; + unsigned int t; + struct device_node *root; + const char *model = ""; + + root = find_path_device("/"); + if (root) + model = get_property(root, "model", NULL); + seq_printf(m, "machine\t\t: CHRP %s\n", model); + + /* longtrail (goldengate) stuff */ + if (!strncmp(model, "IBM,LongTrail", 13)) { + /* VLSI VAS96011/12 `Golden Gate 2' */ + /* Memory banks */ + sdramen = (in_le32(gg2_pci_config_base + GG2_PCI_DRAM_CTRL) + >>31) & 1; + for (i = 0; i < (sdramen ? 4 : 6); i++) { + t = in_le32(gg2_pci_config_base+ + GG2_PCI_DRAM_BANK0+ + i*4); + if (!(t & 1)) + continue; + switch ((t>>8) & 0x1f) { + case 0x1f: + model = "4 MB"; + break; + case 0x1e: + model = "8 MB"; + break; + case 0x1c: + model = "16 MB"; + break; + case 0x18: + model = "32 MB"; + break; + case 0x10: + model = "64 MB"; + break; + case 0x00: + model = "128 MB"; + break; + default: + model = "Reserved"; + break; + } + seq_printf(m, "memory bank %d\t: %s %s\n", i, model, + gg2_memtypes[sdramen ? 1 : ((t>>1) & 3)]); + } + /* L2 cache */ + t = in_le32(gg2_pci_config_base+GG2_PCI_CC_CTRL); + seq_printf(m, "board l2\t: %s %s (%s)\n", + gg2_cachesizes[(t>>7) & 3], + gg2_cachetypes[(t>>2) & 3], + gg2_cachemodes[t & 3]); + } + return 0; +} + +/* + * Fixes for the National Semiconductor PC78308VUL SuperI/O + * + * Some versions of Open Firmware incorrectly initialize the IRQ settings + * for keyboard and mouse + */ +static inline void __init sio_write(u8 val, u8 index) +{ + outb(index, 0x15c); + outb(val, 0x15d); +} + +static inline u8 __init sio_read(u8 index) +{ + outb(index, 0x15c); + return inb(0x15d); +} + +static void __init sio_fixup_irq(const char *name, u8 device, u8 level, + u8 type) +{ + u8 level0, type0, active; + + /* select logical device */ + sio_write(device, 0x07); + active = sio_read(0x30); + level0 = sio_read(0x70); + type0 = sio_read(0x71); + if (level0 != level || type0 != type || !active) { + printk(KERN_WARNING "sio: %s irq level %d, type %d, %sactive: " + "remapping to level %d, type %d, active\n", + name, level0, type0, !active ? "in" : "", level, type); + sio_write(0x01, 0x30); + sio_write(level, 0x70); + sio_write(type, 0x71); + } +} + +static void __init sio_init(void) +{ + struct device_node *root; + + if ((root = find_path_device("/")) && + !strncmp(get_property(root, "model", NULL), "IBM,LongTrail", 13)) { + /* logical device 0 (KBC/Keyboard) */ + sio_fixup_irq("keyboard", 0, 1, 2); + /* select logical device 1 (KBC/Mouse) */ + sio_fixup_irq("mouse", 1, 12, 2); + } +} + + +static void __init pegasos_set_l2cr(void) +{ + struct device_node *np; + + /* On Pegasos, enable the l2 cache if needed, as the OF forgets it */ + if (_chrp_type != _CHRP_Pegasos) + return; + + /* Enable L2 cache if needed */ + np = find_type_devices("cpu"); + if (np != NULL) { + unsigned int *l2cr = (unsigned int *) + get_property (np, "l2cr", NULL); + if (l2cr == NULL) { + printk ("Pegasos l2cr : no cpu l2cr property found\n"); + return; + } + if (!((*l2cr) & 0x80000000)) { + printk ("Pegasos l2cr : L2 cache was not active, " + "activating\n"); + _set_L2CR(0); + _set_L2CR((*l2cr) | 0x80000000); + } + } +} + +void __init chrp_setup_arch(void) +{ + struct device_node *device; + + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000/HZ; + +#ifdef CONFIG_BLK_DEV_INITRD + /* this is fine for chrp */ + initrd_below_start_ok = 1; + + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif + ROOT_DEV = Root_SDA2; /* sda2 (sda1 is for the kernel) */ + + /* On pegasos, enable the L2 cache if not already done by OF */ + pegasos_set_l2cr(); + + /* Lookup PCI host bridges */ + chrp_find_bridges(); + +#ifndef CONFIG_PPC64BRIDGE + /* + * Temporary fixes for PCI devices. + * -- Geert + */ + hydra_init(); /* Mac I/O */ + +#endif /* CONFIG_PPC64BRIDGE */ + + /* + * Fix the Super I/O configuration + */ + sio_init(); + + /* Get the event scan rate for the rtas so we know how + * often it expects a heartbeat. -- Cort + */ + if ( rtas_data ) { + struct property *p; + device = find_devices("rtas"); + for ( p = device->properties; + p && strncmp(p->name, "rtas-event-scan-rate", 20); + p = p->next ) + /* nothing */ ; + if ( p && *(unsigned long *)p->value ) { + ppc_md.heartbeat = chrp_event_scan; + ppc_md.heartbeat_reset = (HZ/(*(unsigned long *)p->value)*30)-1; + ppc_md.heartbeat_count = 1; + printk("RTAS Event Scan Rate: %lu (%lu jiffies)\n", + *(unsigned long *)p->value, ppc_md.heartbeat_reset ); + } + } + + pci_create_OF_bus_map(); +} + +void __chrp +chrp_event_scan(void) +{ + unsigned char log[1024]; + unsigned long ret = 0; + /* XXX: we should loop until the hardware says no more error logs -- Cort */ + call_rtas( "event-scan", 4, 1, &ret, 0xffffffff, 0, + __pa(log), 1024 ); + ppc_md.heartbeat_count = ppc_md.heartbeat_reset; +} + +void __chrp +chrp_restart(char *cmd) +{ + printk("RTAS system-reboot returned %d\n", + call_rtas("system-reboot", 0, 1, NULL)); + for (;;); +} + +void __chrp +chrp_power_off(void) +{ + /* allow power on only with power button press */ + printk("RTAS power-off returned %d\n", + call_rtas("power-off", 2, 1, NULL,0xffffffff,0xffffffff)); + for (;;); +} + +void __chrp +chrp_halt(void) +{ + chrp_power_off(); +} + +u_int __chrp +chrp_irq_canonicalize(u_int irq) +{ + if (irq == 2) + return 9; + return irq; +} + +/* + * Finds the open-pic node and sets OpenPIC_Addr based on its reg property. + * Then checks if it has an interrupt-ranges property. If it does then + * we have a distributed open-pic, so call openpic_set_sources to tell + * the openpic code where to find the interrupt source registers. + */ +static void __init chrp_find_openpic(void) +{ + struct device_node *np; + int len, i; + unsigned int *iranges; + void *isu; + + np = find_type_devices("open-pic"); + if (np == NULL || np->n_addrs == 0) + return; + printk(KERN_INFO "OpenPIC at %x (size %x)\n", + np->addrs[0].address, np->addrs[0].size); + OpenPIC_Addr = ioremap(np->addrs[0].address, 0x40000); + if (OpenPIC_Addr == NULL) { + printk(KERN_ERR "Failed to map OpenPIC!\n"); + return; + } + + iranges = (unsigned int *) get_property(np, "interrupt-ranges", &len); + if (iranges == NULL || len < 2 * sizeof(unsigned int)) + return; /* not distributed */ + + /* + * The first pair of cells in interrupt-ranges refers to the + * IDU; subsequent pairs refer to the ISUs. + */ + len /= 2 * sizeof(unsigned int); + if (np->n_addrs < len) { + printk(KERN_ERR "Insufficient addresses for distributed" + " OpenPIC (%d < %d)\n", np->n_addrs, len); + return; + } + if (iranges[1] != 0) { + printk(KERN_INFO "OpenPIC irqs %d..%d in IDU\n", + iranges[0], iranges[0] + iranges[1] - 1); + openpic_set_sources(iranges[0], iranges[1], NULL); + } + for (i = 1; i < len; ++i) { + iranges += 2; + printk(KERN_INFO "OpenPIC irqs %d..%d in ISU at %x (%x)\n", + iranges[0], iranges[0] + iranges[1] - 1, + np->addrs[i].address, np->addrs[i].size); + isu = ioremap(np->addrs[i].address, np->addrs[i].size); + if (isu != NULL) + openpic_set_sources(iranges[0], iranges[1], isu); + else + printk(KERN_ERR "Failed to map OpenPIC ISU at %x!\n", + np->addrs[i].address); + } +} + +#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) +static struct irqaction xmon_irqaction = { + .handler = xmon_irq, + .mask = CPU_MASK_NONE, + .name = "XMON break", +}; +#endif + +void __init chrp_init_IRQ(void) +{ + struct device_node *np; + int i; + unsigned long chrp_int_ack = 0; + unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS]; +#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) + struct device_node *kbd; +#endif + + for (np = find_devices("pci"); np != NULL; np = np->next) { + unsigned int *addrp = (unsigned int *) + get_property(np, "8259-interrupt-acknowledge", NULL); + + if (addrp == NULL) + continue; + chrp_int_ack = addrp[prom_n_addr_cells(np)-1]; + break; + } + if (np == NULL) + printk(KERN_ERR "Cannot find PCI interrupt acknowledge address\n"); + + chrp_find_openpic(); + + if (OpenPIC_Addr) { + prom_get_irq_senses(init_senses, NUM_8259_INTERRUPTS, NR_IRQS); + OpenPIC_InitSenses = init_senses; + OpenPIC_NumInitSenses = NR_IRQS - NUM_8259_INTERRUPTS; + + openpic_init(NUM_8259_INTERRUPTS); + /* We have a cascade on OpenPIC IRQ 0, Linux IRQ 16 */ + openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade", + i8259_irq); + + } + for (i = 0; i < NUM_8259_INTERRUPTS; i++) + irq_desc[i].handler = &i8259_pic; + i8259_init(chrp_int_ack); + +#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) + /* see if there is a keyboard in the device tree + with a parent of type "adb" */ + for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next) + if (kbd->parent && kbd->parent->type + && strcmp(kbd->parent->type, "adb") == 0) + break; + if (kbd) + setup_irq(HYDRA_INT_ADB_NMI, &xmon_irqaction); +#endif +} + +void __init +chrp_init2(void) +{ +#ifdef CONFIG_NVRAM +// XX replace this in a more saner way +// pmac_nvram_init(); +#endif + + request_region(0x20,0x20,"pic1"); + request_region(0xa0,0x20,"pic2"); + request_region(0x00,0x20,"dma1"); + request_region(0x40,0x20,"timer"); + request_region(0x80,0x10,"dma page reg"); + request_region(0xc0,0x20,"dma2"); + + if (ppc_md.progress) + ppc_md.progress(" Have fun! ", 0x7777); +} + +void __init +chrp_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + struct device_node *root = find_path_device ("/"); + char *machine = NULL; + +#ifdef CONFIG_BLK_DEV_INITRD + /* take care of initrd if we have one */ + if ( r6 ) + { + initrd_start = r6 + KERNELBASE; + initrd_end = r6 + r7 + KERNELBASE; + } +#endif /* CONFIG_BLK_DEV_INITRD */ + + ISA_DMA_THRESHOLD = ~0L; + DMA_MODE_READ = 0x44; + DMA_MODE_WRITE = 0x48; + isa_io_base = CHRP_ISA_IO_BASE; /* default value */ + + if (root) + machine = get_property(root, "model", NULL); + if (machine && strncmp(machine, "Pegasos", 7) == 0) { + _chrp_type = _CHRP_Pegasos; + } else if (machine && strncmp(machine, "IBM", 3) == 0) { + _chrp_type = _CHRP_IBM; + } else if (machine && strncmp(machine, "MOT", 3) == 0) { + _chrp_type = _CHRP_Motorola; + } else { + /* Let's assume it is an IBM chrp if all else fails */ + _chrp_type = _CHRP_IBM; + } + + ppc_md.setup_arch = chrp_setup_arch; + ppc_md.show_percpuinfo = of_show_percpuinfo; + ppc_md.show_cpuinfo = chrp_show_cpuinfo; + + ppc_md.irq_canonicalize = chrp_irq_canonicalize; + ppc_md.init_IRQ = chrp_init_IRQ; + if (_chrp_type == _CHRP_Pegasos) + ppc_md.get_irq = i8259_irq; + else + ppc_md.get_irq = openpic_get_irq; + + ppc_md.init = chrp_init2; + + ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot; + + ppc_md.restart = chrp_restart; + ppc_md.power_off = chrp_power_off; + ppc_md.halt = chrp_halt; + + ppc_md.time_init = chrp_time_init; + ppc_md.set_rtc_time = chrp_set_rtc_time; + ppc_md.get_rtc_time = chrp_get_rtc_time; + ppc_md.calibrate_decr = chrp_calibrate_decr; + + ppc_md.find_end_of_memory = pmac_find_end_of_memory; + + if (rtas_data) { + struct device_node *rtas; + unsigned int *p; + + rtas = find_devices("rtas"); + if (rtas != NULL) { + if (get_property(rtas, "display-character", NULL)) { + ppc_md.progress = rtas_display_progress; + p = (unsigned int *) get_property + (rtas, "ibm,display-line-length", NULL); + if (p) + max_width = *p; + } else if (get_property(rtas, "set-indicator", NULL)) + ppc_md.progress = rtas_indicator_progress; + } + } +#ifdef CONFIG_BOOTX_TEXT + if (ppc_md.progress == NULL && boot_text_mapped) + ppc_md.progress = btext_progress; +#endif + +#ifdef CONFIG_SMP + ppc_md.smp_ops = &chrp_smp_ops; +#endif /* CONFIG_SMP */ + + /* + * Print the banner, then scroll down so boot progress + * can be printed. -- Cort + */ + if (ppc_md.progress) ppc_md.progress("Linux/PPC "UTS_RELEASE"\n", 0x0); +} + +void __chrp +rtas_display_progress(char *s, unsigned short hex) +{ + int width; + char *os = s; + + if ( call_rtas( "display-character", 1, 1, NULL, '\r' ) ) + return; + + width = max_width; + while ( *os ) + { + if ( (*os == '\n') || (*os == '\r') ) + width = max_width; + else + width--; + call_rtas( "display-character", 1, 1, NULL, *os++ ); + /* if we overwrite the screen length */ + if ( width == 0 ) + while ( (*os != 0) && (*os != '\n') && (*os != '\r') ) + os++; + } + + /*while ( width-- > 0 )*/ + call_rtas( "display-character", 1, 1, NULL, ' ' ); +} + +void __chrp +rtas_indicator_progress(char *s, unsigned short hex) +{ + call_rtas("set-indicator", 3, 1, NULL, 6, 0, hex); +} + +#ifdef CONFIG_BOOTX_TEXT +void +btext_progress(char *s, unsigned short hex) +{ + prom_print(s); + prom_print("\n"); +} +#endif /* CONFIG_BOOTX_TEXT */ diff --git a/arch/ppc/platforms/chrp_smp.c b/arch/ppc/platforms/chrp_smp.c new file mode 100644 index 00000000000..0ea1f7d9e46 --- /dev/null +++ b/arch/ppc/platforms/chrp_smp.c @@ -0,0 +1,98 @@ +/* + * Smp support for CHRP machines. + * + * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great + * deal of code from the sparc and intel versions. + * + * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu> + * + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/interrupt.h> +#include <linux/kernel_stat.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/spinlock.h> + +#include <asm/ptrace.h> +#include <asm/atomic.h> +#include <asm/irq.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/sections.h> +#include <asm/io.h> +#include <asm/prom.h> +#include <asm/smp.h> +#include <asm/residual.h> +#include <asm/time.h> +#include <asm/open_pic.h> + +extern unsigned long smp_chrp_cpu_nr; + +static int __init +smp_chrp_probe(void) +{ + if (smp_chrp_cpu_nr > 1) + openpic_request_IPIs(); + + return smp_chrp_cpu_nr; +} + +static void __devinit +smp_chrp_kick_cpu(int nr) +{ + *(unsigned long *)KERNELBASE = nr; + asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory"); +} + +static void __devinit +smp_chrp_setup_cpu(int cpu_nr) +{ + if (OpenPIC_Addr) + do_openpic_setup_cpu(); +} + +static DEFINE_SPINLOCK(timebase_lock); +static unsigned int timebase_upper = 0, timebase_lower = 0; + +void __devinit +smp_chrp_give_timebase(void) +{ + spin_lock(&timebase_lock); + call_rtas("freeze-time-base", 0, 1, NULL); + timebase_upper = get_tbu(); + timebase_lower = get_tbl(); + spin_unlock(&timebase_lock); + + while (timebase_upper || timebase_lower) + barrier(); + call_rtas("thaw-time-base", 0, 1, NULL); +} + +void __devinit +smp_chrp_take_timebase(void) +{ + while (!(timebase_upper || timebase_lower)) + barrier(); + spin_lock(&timebase_lock); + set_tb(timebase_upper, timebase_lower); + timebase_upper = 0; + timebase_lower = 0; + spin_unlock(&timebase_lock); + printk("CPU %i taken timebase\n", smp_processor_id()); +} + +/* CHRP with openpic */ +struct smp_ops_t chrp_smp_ops __chrpdata = { + .message_pass = smp_openpic_message_pass, + .probe = smp_chrp_probe, + .kick_cpu = smp_chrp_kick_cpu, + .setup_cpu = smp_chrp_setup_cpu, + .give_timebase = smp_chrp_give_timebase, + .take_timebase = smp_chrp_take_timebase, +}; diff --git a/arch/ppc/platforms/chrp_time.c b/arch/ppc/platforms/chrp_time.c new file mode 100644 index 00000000000..e2be0c838d8 --- /dev/null +++ b/arch/ppc/platforms/chrp_time.c @@ -0,0 +1,194 @@ +/* + * arch/ppc/platforms/chrp_time.c + * + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * + * Adapted for PowerPC (PReP) by Gary Thomas + * Modified by Cort Dougan (cort@cs.nmt.edu). + * Copied and modified from arch/i386/kernel/time.c + * + */ +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/param.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/interrupt.h> +#include <linux/time.h> +#include <linux/timex.h> +#include <linux/kernel_stat.h> +#include <linux/mc146818rtc.h> +#include <linux/init.h> +#include <linux/bcd.h> + +#include <asm/segment.h> +#include <asm/io.h> +#include <asm/nvram.h> +#include <asm/prom.h> +#include <asm/sections.h> +#include <asm/time.h> + +extern spinlock_t rtc_lock; + +static int nvram_as1 = NVRAM_AS1; +static int nvram_as0 = NVRAM_AS0; +static int nvram_data = NVRAM_DATA; + +long __init chrp_time_init(void) +{ + struct device_node *rtcs; + int base; + + rtcs = find_compatible_devices("rtc", "pnpPNP,b00"); + if (rtcs == NULL) + rtcs = find_compatible_devices("rtc", "ds1385-rtc"); + if (rtcs == NULL || rtcs->addrs == NULL) + return 0; + base = rtcs->addrs[0].address; + nvram_as1 = 0; + nvram_as0 = base; + nvram_data = base + 1; + + return 0; +} + +int __chrp chrp_cmos_clock_read(int addr) +{ + if (nvram_as1 != 0) + outb(addr>>8, nvram_as1); + outb(addr, nvram_as0); + return (inb(nvram_data)); +} + +void __chrp chrp_cmos_clock_write(unsigned long val, int addr) +{ + if (nvram_as1 != 0) + outb(addr>>8, nvram_as1); + outb(addr, nvram_as0); + outb(val, nvram_data); + return; +} + +/* + * Set the hardware clock. -- Cort + */ +int __chrp chrp_set_rtc_time(unsigned long nowtime) +{ + unsigned char save_control, save_freq_select; + struct rtc_time tm; + + spin_lock(&rtc_lock); + to_tm(nowtime, &tm); + + save_control = chrp_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */ + + chrp_cmos_clock_write((save_control|RTC_SET), RTC_CONTROL); + + save_freq_select = chrp_cmos_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */ + + chrp_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + + tm.tm_year -= 1900; + if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BIN_TO_BCD(tm.tm_sec); + BIN_TO_BCD(tm.tm_min); + BIN_TO_BCD(tm.tm_hour); + BIN_TO_BCD(tm.tm_mon); + BIN_TO_BCD(tm.tm_mday); + BIN_TO_BCD(tm.tm_year); + } + chrp_cmos_clock_write(tm.tm_sec,RTC_SECONDS); + chrp_cmos_clock_write(tm.tm_min,RTC_MINUTES); + chrp_cmos_clock_write(tm.tm_hour,RTC_HOURS); + chrp_cmos_clock_write(tm.tm_mon,RTC_MONTH); + chrp_cmos_clock_write(tm.tm_mday,RTC_DAY_OF_MONTH); + chrp_cmos_clock_write(tm.tm_year,RTC_YEAR); + + /* The following flags have to be released exactly in this order, + * otherwise the DS12887 (popular MC146818A clone with integrated + * battery and quartz) will not reset the oscillator and will not + * update precisely 500 ms later. You won't find this mentioned in + * the Dallas Semiconductor data sheets, but who believes data + * sheets anyway ... -- Markus Kuhn + */ + chrp_cmos_clock_write(save_control, RTC_CONTROL); + chrp_cmos_clock_write(save_freq_select, RTC_FREQ_SELECT); + + if ( (time_state == TIME_ERROR) || (time_state == TIME_BAD) ) + time_state = TIME_OK; + spin_unlock(&rtc_lock); + return 0; +} + +unsigned long __chrp chrp_get_rtc_time(void) +{ + unsigned int year, mon, day, hour, min, sec; + int uip, i; + + /* The Linux interpretation of the CMOS clock register contents: + * When the Update-In-Progress (UIP) flag goes from 1 to 0, the + * RTC registers show the second which has precisely just started. + * Let's hope other operating systems interpret the RTC the same way. + */ + + /* Since the UIP flag is set for about 2.2 ms and the clock + * is typically written with a precision of 1 jiffy, trying + * to obtain a precision better than a few milliseconds is + * an illusion. Only consistency is interesting, this also + * allows to use the routine for /dev/rtc without a potential + * 1 second kernel busy loop triggered by any reader of /dev/rtc. + */ + + for ( i = 0; i<1000000; i++) { + uip = chrp_cmos_clock_read(RTC_FREQ_SELECT); + sec = chrp_cmos_clock_read(RTC_SECONDS); + min = chrp_cmos_clock_read(RTC_MINUTES); + hour = chrp_cmos_clock_read(RTC_HOURS); + day = chrp_cmos_clock_read(RTC_DAY_OF_MONTH); + mon = chrp_cmos_clock_read(RTC_MONTH); + year = chrp_cmos_clock_read(RTC_YEAR); + uip |= chrp_cmos_clock_read(RTC_FREQ_SELECT); + if ((uip & RTC_UIP)==0) break; + } + + if (!(chrp_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + { + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + } + if ((year += 1900) < 1970) + year += 100; + return mktime(year, mon, day, hour, min, sec); +} + + +void __init chrp_calibrate_decr(void) +{ + struct device_node *cpu; + unsigned int freq, *fp; + + if (via_calibrate_decr()) + return; + + /* + * The cpu node should have a timebase-frequency property + * to tell us the rate at which the decrementer counts. + */ + freq = 16666000; /* hardcoded default */ + cpu = find_type_devices("cpu"); + if (cpu != 0) { + fp = (unsigned int *) + get_property(cpu, "timebase-frequency", NULL); + if (fp != 0) + freq = *fp; + } + printk("time_init: decrementer frequency = %u.%.6u MHz\n", + freq/1000000, freq%1000000); + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); +} diff --git a/arch/ppc/platforms/cpci690.c b/arch/ppc/platforms/cpci690.c new file mode 100644 index 00000000000..507870c9a97 --- /dev/null +++ b/arch/ppc/platforms/cpci690.c @@ -0,0 +1,491 @@ +/* + * arch/ppc/platforms/cpci690.c + * + * Board setup routines for the Force CPCI690 board. + * + * Author: Mark A. Greer <mgreer@mvista.com> + * + * 2003 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This programr + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ +#include <linux/config.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/ide.h> +#include <linux/irq.h> +#include <linux/fs.h> +#include <linux/seq_file.h> +#include <linux/console.h> +#include <linux/initrd.h> +#include <linux/root_dev.h> +#include <linux/mv643xx.h> +#include <asm/bootinfo.h> +#include <asm/machdep.h> +#include <asm/todc.h> +#include <asm/time.h> +#include <asm/mv64x60.h> +#include <platforms/cpci690.h> + +#define BOARD_VENDOR "Force" +#define BOARD_MACHINE "CPCI690" + +/* Set IDE controllers into Native mode? */ +#define SET_PCI_IDE_NATIVE + +static struct mv64x60_handle bh; +static u32 cpci690_br_base; + +static const unsigned int cpu_7xx[16] = { /* 7xx & 74xx (but not 745x) */ + 18, 15, 14, 2, 4, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0 +}; + +TODC_ALLOC(); + +static int __init +cpci690_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); + + if (hose->index == 0) { + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + { 90, 91, 88, 89}, /* IDSEL 30/20 - Sentinel */ + }; + + const long min_idsel = 20, max_idsel = 20, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; + } else { + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + { 93, 94, 95, 92}, /* IDSEL 28/18 - PMC slot 2 */ + { 0, 0, 0, 0}, /* IDSEL 29/19 - Not used */ + { 94, 95, 92, 93}, /* IDSEL 30/20 - PMC slot 1 */ + }; + + const long min_idsel = 18, max_idsel = 20, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; + } +} + +static int +cpci690_get_cpu_speed(void) +{ + unsigned long hid1; + + hid1 = mfspr(SPRN_HID1) >> 28; + return CPCI690_BUS_FREQ * cpu_7xx[hid1]/2; +} + +#define KB (1024UL) +#define MB (1024UL * KB) +#define GB (1024UL * MB) + +unsigned long __init +cpci690_find_end_of_memory(void) +{ + u32 mem_ctlr_size; + static u32 board_size; + static u8 first_time = 1; + + if (first_time) { + /* Using cpci690_set_bat() mapping ==> virt addr == phys addr */ + switch (in_8((u8 *) (cpci690_br_base + + CPCI690_BR_MEM_CTLR)) & 0x07) { + case 0x01: + board_size = 256*MB; + break; + case 0x02: + board_size = 512*MB; + break; + case 0x03: + board_size = 768*MB; + break; + case 0x04: + board_size = 1*GB; + break; + case 0x05: + board_size = 1*GB + 512*MB; + break; + case 0x06: + board_size = 2*GB; + break; + default: + board_size = 0xffffffff; /* use mem ctlr size */ + } /* switch */ + + mem_ctlr_size = mv64x60_get_mem_size(CONFIG_MV64X60_NEW_BASE, + MV64x60_TYPE_GT64260A); + + /* Check that mem ctlr & board reg agree. If not, pick MIN. */ + if (board_size != mem_ctlr_size) { + printk(KERN_WARNING "Board register & memory controller" + "mem size disagree (board reg: 0x%lx, " + "mem ctlr: 0x%lx)\n", + (ulong)board_size, (ulong)mem_ctlr_size); + board_size = min(board_size, mem_ctlr_size); + } + + first_time = 0; + } /* if */ + + return board_size; +} + +static void __init +cpci690_setup_bridge(void) +{ + struct mv64x60_setup_info si; + int i; + + memset(&si, 0, sizeof(si)); + + si.phys_reg_base = CONFIG_MV64X60_NEW_BASE; + + si.pci_0.enable_bus = 1; + si.pci_0.pci_io.cpu_base = CPCI690_PCI0_IO_START_PROC_ADDR; + si.pci_0.pci_io.pci_base_hi = 0; + si.pci_0.pci_io.pci_base_lo = CPCI690_PCI0_IO_START_PCI_ADDR; + si.pci_0.pci_io.size = CPCI690_PCI0_IO_SIZE; + si.pci_0.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE; + si.pci_0.pci_mem[0].cpu_base = CPCI690_PCI0_MEM_START_PROC_ADDR; + si.pci_0.pci_mem[0].pci_base_hi = CPCI690_PCI0_MEM_START_PCI_HI_ADDR; + si.pci_0.pci_mem[0].pci_base_lo = CPCI690_PCI0_MEM_START_PCI_LO_ADDR; + si.pci_0.pci_mem[0].size = CPCI690_PCI0_MEM_SIZE; + si.pci_0.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE; + si.pci_0.pci_cmd_bits = 0; + si.pci_0.latency_timer = 0x80; + + si.pci_1.enable_bus = 1; + si.pci_1.pci_io.cpu_base = CPCI690_PCI1_IO_START_PROC_ADDR; + si.pci_1.pci_io.pci_base_hi = 0; + si.pci_1.pci_io.pci_base_lo = CPCI690_PCI1_IO_START_PCI_ADDR; + si.pci_1.pci_io.size = CPCI690_PCI1_IO_SIZE; + si.pci_1.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE; + si.pci_1.pci_mem[0].cpu_base = CPCI690_PCI1_MEM_START_PROC_ADDR; + si.pci_1.pci_mem[0].pci_base_hi = CPCI690_PCI1_MEM_START_PCI_HI_ADDR; + si.pci_1.pci_mem[0].pci_base_lo = CPCI690_PCI1_MEM_START_PCI_LO_ADDR; + si.pci_1.pci_mem[0].size = CPCI690_PCI1_MEM_SIZE; + si.pci_1.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE; + si.pci_1.pci_cmd_bits = 0; + si.pci_1.latency_timer = 0x80; + + for (i=0; i<MV64x60_CPU2MEM_WINDOWS; i++) { + si.cpu_prot_options[i] = 0; + si.cpu_snoop_options[i] = GT64260_CPU_SNOOP_WB; + si.pci_0.acc_cntl_options[i] = + GT64260_PCI_ACC_CNTL_DREADEN | + GT64260_PCI_ACC_CNTL_RDPREFETCH | + GT64260_PCI_ACC_CNTL_RDLINEPREFETCH | + GT64260_PCI_ACC_CNTL_RDMULPREFETCH | + GT64260_PCI_ACC_CNTL_SWAP_NONE | + GT64260_PCI_ACC_CNTL_MBURST_32_BTYES; + si.pci_0.snoop_options[i] = GT64260_PCI_SNOOP_WB; + si.pci_1.acc_cntl_options[i] = + GT64260_PCI_ACC_CNTL_DREADEN | + GT64260_PCI_ACC_CNTL_RDPREFETCH | + GT64260_PCI_ACC_CNTL_RDLINEPREFETCH | + GT64260_PCI_ACC_CNTL_RDMULPREFETCH | + GT64260_PCI_ACC_CNTL_SWAP_NONE | + GT64260_PCI_ACC_CNTL_MBURST_32_BTYES; + si.pci_1.snoop_options[i] = GT64260_PCI_SNOOP_WB; + } + + /* Lookup PCI host bridges */ + if (mv64x60_init(&bh, &si)) + printk(KERN_ERR "Bridge initialization failed.\n"); + + pci_dram_offset = 0; /* System mem at same addr on PCI & cpu bus */ + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = cpci690_map_irq; + ppc_md.pci_exclude_device = mv64x60_pci_exclude_device; + + mv64x60_set_bus(&bh, 0, 0); + bh.hose_a->first_busno = 0; + bh.hose_a->last_busno = 0xff; + bh.hose_a->last_busno = pciauto_bus_scan(bh.hose_a, 0); + + bh.hose_b->first_busno = bh.hose_a->last_busno + 1; + mv64x60_set_bus(&bh, 1, bh.hose_b->first_busno); + bh.hose_b->last_busno = 0xff; + bh.hose_b->last_busno = pciauto_bus_scan(bh.hose_b, + bh.hose_b->first_busno); +} + +static void __init +cpci690_setup_peripherals(void) +{ + /* Set up windows to CPLD, RTC/TODC, IPMI. */ + mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_0_WIN, CPCI690_BR_BASE, + CPCI690_BR_SIZE, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_0_WIN); + cpci690_br_base = (u32)ioremap(CPCI690_BR_BASE, CPCI690_BR_SIZE); + + mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN, CPCI690_TODC_BASE, + CPCI690_TODC_SIZE, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_1_WIN); + TODC_INIT(TODC_TYPE_MK48T35, 0, 0, + ioremap(CPCI690_TODC_BASE, CPCI690_TODC_SIZE), 8); + + mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_2_WIN, CPCI690_IPMI_BASE, + CPCI690_IPMI_SIZE, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_2_WIN); + + mv64x60_set_bits(&bh, MV64x60_PCI0_ARBITER_CNTL, (1<<31)); + mv64x60_set_bits(&bh, MV64x60_PCI1_ARBITER_CNTL, (1<<31)); + + mv64x60_set_bits(&bh, MV64x60_CPU_MASTER_CNTL, (1<<9)); /* Only 1 cpu */ + + /* + * Turn off timer/counters. Not turning off watchdog timer because + * can't read its reg on the 64260A so don't know if we'll be enabling + * or disabling. + */ + mv64x60_clr_bits(&bh, MV64x60_TIMR_CNTR_0_3_CNTL, + ((1<<0) | (1<<8) | (1<<16) | (1<<24))); + mv64x60_clr_bits(&bh, GT64260_TIMR_CNTR_4_7_CNTL, + ((1<<0) | (1<<8) | (1<<16) | (1<<24))); + + /* + * Set MPSC Multiplex RMII + * NOTE: ethernet driver modifies bit 0 and 1 + */ + mv64x60_write(&bh, GT64260_MPP_SERIAL_PORTS_MULTIPLEX, 0x00001102); + +#define GPP_EXTERNAL_INTERRUPTS \ + ((1<<24) | (1<<25) | (1<<26) | (1<<27) | \ + (1<<28) | (1<<29) | (1<<30) | (1<<31)) + /* PCI interrupts are inputs */ + mv64x60_clr_bits(&bh, MV64x60_GPP_IO_CNTL, GPP_EXTERNAL_INTERRUPTS); + /* PCI interrupts are active low */ + mv64x60_set_bits(&bh, MV64x60_GPP_LEVEL_CNTL, GPP_EXTERNAL_INTERRUPTS); + + /* Clear any pending interrupts for these inputs and enable them. */ + mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, ~GPP_EXTERNAL_INTERRUPTS); + mv64x60_set_bits(&bh, MV64x60_GPP_INTR_MASK, GPP_EXTERNAL_INTERRUPTS); + + /* Route MPP interrupt inputs to GPP */ + mv64x60_write(&bh, MV64x60_MPP_CNTL_2, 0x00000000); + mv64x60_write(&bh, MV64x60_MPP_CNTL_3, 0x00000000); +} + +static void __init +cpci690_setup_arch(void) +{ + if (ppc_md.progress) + ppc_md.progress("cpci690_setup_arch: enter", 0); +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_SDA2; +#endif + + if (ppc_md.progress) + ppc_md.progress("cpci690_setup_arch: Enabling L2 cache", 0); + + /* Enable L2 and L3 caches (if 745x) */ + _set_L2CR(_get_L2CR() | L2CR_L2E); + _set_L3CR(_get_L3CR() | L3CR_L3E); + + if (ppc_md.progress) + ppc_md.progress("cpci690_setup_arch: Initializing bridge", 0); + + cpci690_setup_bridge(); /* set up PCI bridge(s) */ + cpci690_setup_peripherals(); /* set up chip selects/GPP/MPP etc */ + + if (ppc_md.progress) + ppc_md.progress("cpci690_setup_arch: bridge init complete", 0); + + printk(KERN_INFO "%s %s port (C) 2003 MontaVista Software, Inc. " + "(source@mvista.com)\n", BOARD_VENDOR, BOARD_MACHINE); + + if (ppc_md.progress) + ppc_md.progress("cpci690_setup_arch: exit", 0); +} + +/* Platform device data fixup routines. */ +#if defined(CONFIG_SERIAL_MPSC) +static void __init +cpci690_fixup_mpsc_pdata(struct platform_device *pdev) +{ + struct mpsc_pdata *pdata; + + pdata = (struct mpsc_pdata *)pdev->dev.platform_data; + + pdata->max_idle = 40; + pdata->default_baud = CPCI690_MPSC_BAUD; + pdata->brg_clk_src = CPCI690_MPSC_CLK_SRC; + pdata->brg_clk_freq = CPCI690_BUS_FREQ; +} + +static int __init +cpci690_platform_notify(struct device *dev) +{ + static struct { + char *bus_id; + void ((*rtn)(struct platform_device *pdev)); + } dev_map[] = { + { MPSC_CTLR_NAME ".0", cpci690_fixup_mpsc_pdata }, + { MPSC_CTLR_NAME ".1", cpci690_fixup_mpsc_pdata }, + }; + struct platform_device *pdev; + int i; + + if (dev && dev->bus_id) + for (i=0; i<ARRAY_SIZE(dev_map); i++) + if (!strncmp(dev->bus_id, dev_map[i].bus_id, + BUS_ID_SIZE)) { + + pdev = container_of(dev, + struct platform_device, dev); + dev_map[i].rtn(pdev); + } + + return 0; +} +#endif + +static void +cpci690_reset_board(void) +{ + u32 i = 10000; + + local_irq_disable(); + out_8((u8 *)(cpci690_br_base + CPCI690_BR_SW_RESET), 0x11); + + while (i != 0) i++; + panic("restart failed\n"); +} + +static void +cpci690_restart(char *cmd) +{ + cpci690_reset_board(); +} + +static void +cpci690_halt(void) +{ + while (1); + /* NOTREACHED */ +} + +static void +cpci690_power_off(void) +{ + cpci690_halt(); + /* NOTREACHED */ +} + +static int +cpci690_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "vendor\t\t: " BOARD_VENDOR "\n"); + seq_printf(m, "machine\t\t: " BOARD_MACHINE "\n"); + seq_printf(m, "cpu MHz\t\t: %d\n", cpci690_get_cpu_speed()/1000/1000); + seq_printf(m, "bus MHz\t\t: %d\n", CPCI690_BUS_FREQ/1000/1000); + + return 0; +} + +static void __init +cpci690_calibrate_decr(void) +{ + ulong freq; + + freq = CPCI690_BUS_FREQ / 4; + + printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n", + freq/1000000, freq%1000000); + + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); +} + +static __inline__ void +cpci690_set_bat(u32 addr, u32 size) +{ + addr &= 0xfffe0000; + size &= 0x1ffe0000; + size = ((size >> 17) - 1) << 2; + + mb(); + mtspr(SPRN_DBAT1U, addr | size | 0x2); /* Vs == 1; Vp == 0 */ + mtspr(SPRN_DBAT1L, addr | 0x2a); /* WIMG bits == 0101; PP == r/w access */ + mb(); +} + +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) +static void __init +cpci690_map_io(void) +{ + io_block_mapping(CONFIG_MV64X60_NEW_BASE, CONFIG_MV64X60_NEW_BASE, + 128 * KB, _PAGE_IO); +} +#endif + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ +#ifdef CONFIG_BLK_DEV_INITRD + initrd_start=initrd_end=0; + initrd_below_start_ok=0; +#endif /* CONFIG_BLK_DEV_INITRD */ + + parse_bootinfo(find_bootinfo()); + + loops_per_jiffy = cpci690_get_cpu_speed() / HZ; + + isa_mem_base = 0; + + ppc_md.setup_arch = cpci690_setup_arch; + ppc_md.show_cpuinfo = cpci690_show_cpuinfo; + ppc_md.init_IRQ = gt64260_init_irq; + ppc_md.get_irq = gt64260_get_irq; + ppc_md.restart = cpci690_restart; + ppc_md.power_off = cpci690_power_off; + ppc_md.halt = cpci690_halt; + ppc_md.find_end_of_memory = cpci690_find_end_of_memory; + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; + ppc_md.calibrate_decr = cpci690_calibrate_decr; + + /* + * Need to map in board regs (used by cpci690_find_end_of_memory()) + * and the bridge's regs (used by progress); + */ + cpci690_set_bat(CPCI690_BR_BASE, 32 * MB); + cpci690_br_base = CPCI690_BR_BASE; + +#ifdef CONFIG_SERIAL_TEXT_DEBUG + ppc_md.setup_io_mappings = cpci690_map_io; + ppc_md.progress = mv64x60_mpsc_progress; + mv64x60_progress_init(CONFIG_MV64X60_NEW_BASE); +#endif /* CONFIG_SERIAL_TEXT_DEBUG */ +#ifdef CONFIG_KGDB + ppc_md.setup_io_mappings = cpci690_map_io; + ppc_md.early_serial_map = cpci690_early_serial_map; +#endif /* CONFIG_KGDB */ + +#if defined(CONFIG_SERIAL_MPSC) + platform_notify = cpci690_platform_notify; +#endif +} diff --git a/arch/ppc/platforms/cpci690.h b/arch/ppc/platforms/cpci690.h new file mode 100644 index 00000000000..36cd2673c74 --- /dev/null +++ b/arch/ppc/platforms/cpci690.h @@ -0,0 +1,78 @@ +/* + * arch/ppc/platforms/cpci690.h + * + * Definitions for Force CPCI690 + * + * Author: Mark A. Greer <mgreer@mvista.com> + * + * 2003 (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. + */ + +/* + * The GT64260 has 2 PCI buses each with 1 window from the CPU bus to + * PCI I/O space and 4 windows from the CPU bus to PCI MEM space. + */ + +#ifndef __PPC_PLATFORMS_CPCI690_H +#define __PPC_PLATFORMS_CPCI690_H + +/* + * Define bd_t to pass in the MAC addresses used by the GT64260's enet ctlrs. + */ +#define CPCI690_BI_MAGIC 0xFE8765DC + +typedef struct board_info { + u32 bi_magic; + u8 bi_enetaddr[3][6]; +} bd_t; + +/* PCI bus Resource setup */ +#define CPCI690_PCI0_MEM_START_PROC_ADDR 0x80000000 +#define CPCI690_PCI0_MEM_START_PCI_HI_ADDR 0x00000000 +#define CPCI690_PCI0_MEM_START_PCI_LO_ADDR 0x80000000 +#define CPCI690_PCI0_MEM_SIZE 0x10000000 +#define CPCI690_PCI0_IO_START_PROC_ADDR 0xa0000000 +#define CPCI690_PCI0_IO_START_PCI_ADDR 0x00000000 +#define CPCI690_PCI0_IO_SIZE 0x01000000 + +#define CPCI690_PCI1_MEM_START_PROC_ADDR 0x90000000 +#define CPCI690_PCI1_MEM_START_PCI_HI_ADDR 0x00000000 +#define CPCI690_PCI1_MEM_START_PCI_LO_ADDR 0x90000000 +#define CPCI690_PCI1_MEM_SIZE 0x10000000 +#define CPCI690_PCI1_IO_START_PROC_ADDR 0xa1000000 +#define CPCI690_PCI1_IO_START_PCI_ADDR 0x01000000 +#define CPCI690_PCI1_IO_SIZE 0x01000000 + +/* Board Registers */ +#define CPCI690_BR_BASE 0xf0000000 +#define CPCI690_BR_SIZE_ACTUAL 0x8 +#define CPCI690_BR_SIZE max(GT64260_WINDOW_SIZE_MIN, \ + CPCI690_BR_SIZE_ACTUAL) +#define CPCI690_BR_LED_CNTL 0x00 +#define CPCI690_BR_SW_RESET 0x01 +#define CPCI690_BR_MISC_STATUS 0x02 +#define CPCI690_BR_SWITCH_STATUS 0x03 +#define CPCI690_BR_MEM_CTLR 0x04 +#define CPCI690_BR_LAST_RESET_1 0x05 +#define CPCI690_BR_LAST_RESET_2 0x06 + +#define CPCI690_TODC_BASE 0xf0100000 +#define CPCI690_TODC_SIZE_ACTUAL 0x8000 /* Size or NVRAM + RTC */ +#define CPCI690_TODC_SIZE max(GT64260_WINDOW_SIZE_MIN, \ + CPCI690_TODC_SIZE_ACTUAL) +#define CPCI690_MAC_OFFSET 0x7c10 /* MAC in RTC NVRAM */ + +#define CPCI690_IPMI_BASE 0xf0200000 +#define CPCI690_IPMI_SIZE_ACTUAL 0x10 /* 16 bytes of IPMI */ +#define CPCI690_IPMI_SIZE max(GT64260_WINDOW_SIZE_MIN, \ + CPCI690_IPMI_SIZE_ACTUAL) + +#define CPCI690_MPSC_BAUD 9600 +#define CPCI690_MPSC_CLK_SRC 8 /* TCLK */ + +#define CPCI690_BUS_FREQ 133333333 + +#endif /* __PPC_PLATFORMS_CPCI690_H */ diff --git a/arch/ppc/platforms/est8260.h b/arch/ppc/platforms/est8260.h new file mode 100644 index 00000000000..adba68ecf57 --- /dev/null +++ b/arch/ppc/platforms/est8260.h @@ -0,0 +1,35 @@ +/* Board information for the EST8260, which should be generic for + * all 8260 boards. The IMMR is now given to us so the hard define + * will soon be removed. All of the clock values are computed from + * the configuration SCMR and the Power-On-Reset word. + */ +#ifndef __EST8260_PLATFORM +#define __EST8260_PLATFORM + +#define CPM_MAP_ADDR ((uint)0xf0000000) + +#define BOOTROM_RESTART_ADDR ((uint)0xff000104) + +/* For our show_cpuinfo hooks. */ +#define CPUINFO_VENDOR "EST Corporation" +#define CPUINFO_MACHINE "SBC8260 PowerPC" + +/* A Board Information structure that is given to a program when + * prom starts it up. + */ +typedef struct bd_info { + unsigned int bi_memstart; /* Memory start address */ + unsigned int bi_memsize; /* Memory (end) size in bytes */ + unsigned int bi_intfreq; /* Internal Freq, in Hz */ + unsigned int bi_busfreq; /* Bus Freq, in MHz */ + unsigned int bi_cpmfreq; /* CPM Freq, in MHz */ + unsigned int bi_brgfreq; /* BRG Freq, in MHz */ + unsigned int bi_vco; /* VCO Out from PLL */ + unsigned int bi_baudrate; /* Default console baud rate */ + unsigned int bi_immr; /* IMMR when called from boot rom */ + unsigned char bi_enetaddr[6]; +} bd_t; + +extern bd_t m8xx_board_info; + +#endif /* __EST8260_PLATFORM */ diff --git a/arch/ppc/platforms/ev64260.c b/arch/ppc/platforms/ev64260.c new file mode 100644 index 00000000000..aa50637a5cf --- /dev/null +++ b/arch/ppc/platforms/ev64260.c @@ -0,0 +1,651 @@ +/* + * arch/ppc/platforms/ev64260.c + * + * Board setup routines for the Marvell/Galileo EV-64260-BP Evaluation Board. + * + * Author: Mark A. Greer <mgreer@mvista.com> + * + * 2001-2003 (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. + */ + +/* + * The EV-64260-BP port is the result of hard work from many people from + * many companies. In particular, employees of Marvell/Galileo, Mission + * Critical Linux, Xyterra, and MontaVista Software were heavily involved. + * + * Note: I have not been able to get *all* PCI slots to work reliably + * at 66 MHz. I recommend setting jumpers J15 & J16 to short pins 1&2 + * so that 33 MHz is used. --MAG + * Note: The 750CXe and 7450 are not stable with a 125MHz or 133MHz TCLK/SYSCLK. + * At 100MHz, they are solid. + */ +#include <linux/config.h> + +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/ide.h> +#include <linux/irq.h> +#include <linux/fs.h> +#include <linux/seq_file.h> +#include <linux/console.h> +#include <linux/initrd.h> +#include <linux/root_dev.h> +#if !defined(CONFIG_SERIAL_MPSC_CONSOLE) +#include <linux/serial.h> +#include <linux/tty.h> +#include <linux/serial_core.h> +#else +#include <linux/mv643xx.h> +#endif +#include <asm/bootinfo.h> +#include <asm/machdep.h> +#include <asm/mv64x60.h> +#include <asm/todc.h> +#include <asm/time.h> + +#include <platforms/ev64260.h> + +#define BOARD_VENDOR "Marvell/Galileo" +#define BOARD_MACHINE "EV-64260-BP" + +static struct mv64x60_handle bh; + +#if !defined(CONFIG_SERIAL_MPSC_CONSOLE) +extern void gen550_progress(char *, unsigned short); +extern void gen550_init(int, struct uart_port *); +#endif + +static const unsigned int cpu_7xx[16] = { /* 7xx & 74xx (but not 745x) */ + 18, 15, 14, 2, 4, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0 +}; +static const unsigned int cpu_745x[2][16] = { /* PLL_EXT 0 & 1 */ + { 1, 15, 14, 2, 4, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0 }, + { 0, 30, 0, 2, 0, 26, 0, 18, 0, 22, 20, 24, 28, 32, 0, 0 } +}; + + +TODC_ALLOC(); + +static int +ev64260_get_bus_speed(void) +{ + return 100000000; +} + +static int +ev64260_get_cpu_speed(void) +{ + unsigned long pvr, hid1, pll_ext; + + pvr = PVR_VER(mfspr(SPRN_PVR)); + + if (pvr != PVR_VER(PVR_7450)) { + hid1 = mfspr(SPRN_HID1) >> 28; + return ev64260_get_bus_speed() * cpu_7xx[hid1]/2; + } + else { + hid1 = (mfspr(SPRN_HID1) & 0x0001e000) >> 13; + pll_ext = 0; /* No way to read; must get from schematic */ + return ev64260_get_bus_speed() * cpu_745x[pll_ext][hid1]/2; + } +} + +unsigned long __init +ev64260_find_end_of_memory(void) +{ + return mv64x60_get_mem_size(CONFIG_MV64X60_NEW_BASE, + MV64x60_TYPE_GT64260A); +} + +/* + * Marvell/Galileo EV-64260-BP Evaluation Board PCI interrupt routing. + * Note: By playing with J8 and JP1-4, you can get 2 IRQ's from the first + * PCI bus (in which cast, INTPIN B would be EV64260_PCI_1_IRQ). + * This is the most IRQs you can get from one bus with this board, though. + */ +static int __init +ev64260_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); + + if (hose->index == 0) { + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {EV64260_PCI_0_IRQ,0,0,0}, /* IDSEL 7 - PCI bus 0 */ + {EV64260_PCI_0_IRQ,0,0,0}, /* IDSEL 8 - PCI bus 0 */ + }; + + const long min_idsel = 7, max_idsel = 8, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; + } + else { + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + { EV64260_PCI_1_IRQ,0,0,0}, /* IDSEL 7 - PCI bus 1 */ + { EV64260_PCI_1_IRQ,0,0,0}, /* IDSEL 8 - PCI bus 1 */ + }; + + const long min_idsel = 7, max_idsel = 8, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; + } +} + +static void __init +ev64260_setup_peripherals(void) +{ + mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN, + EV64260_EMB_FLASH_BASE, EV64260_EMB_FLASH_SIZE, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN); + mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_0_WIN, + EV64260_EXT_SRAM_BASE, EV64260_EXT_SRAM_SIZE, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_0_WIN); + mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN, + EV64260_TODC_BASE, EV64260_TODC_SIZE, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_1_WIN); + mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_2_WIN, + EV64260_UART_BASE, EV64260_UART_SIZE, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_2_WIN); + mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_3_WIN, + EV64260_EXT_FLASH_BASE, EV64260_EXT_FLASH_SIZE, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_3_WIN); + + TODC_INIT(TODC_TYPE_DS1501, 0, 0, + ioremap(EV64260_TODC_BASE, EV64260_TODC_SIZE), 8); + + mv64x60_clr_bits(&bh, MV64x60_CPU_CONFIG,((1<<12) | (1<<28) | (1<<29))); + mv64x60_set_bits(&bh, MV64x60_CPU_CONFIG, (1<<27)); + + if (ev64260_get_bus_speed() > 100000000) + mv64x60_set_bits(&bh, MV64x60_CPU_CONFIG, (1<<23)); + + mv64x60_set_bits(&bh, MV64x60_PCI0_PCI_DECODE_CNTL, ((1<<0) | (1<<3))); + mv64x60_set_bits(&bh, MV64x60_PCI1_PCI_DECODE_CNTL, ((1<<0) | (1<<3))); + + /* + * Enabling of PCI internal-vs-external arbitration + * is a platform- and errata-dependent decision. + */ + if (bh.type == MV64x60_TYPE_GT64260A ) { + mv64x60_set_bits(&bh, MV64x60_PCI0_ARBITER_CNTL, (1<<31)); + mv64x60_set_bits(&bh, MV64x60_PCI1_ARBITER_CNTL, (1<<31)); + } + + mv64x60_set_bits(&bh, MV64x60_CPU_MASTER_CNTL, (1<<9)); /* Only 1 cpu */ + + /* + * Turn off timer/counters. Not turning off watchdog timer because + * can't read its reg on the 64260A so don't know if we'll be enabling + * or disabling. + */ + mv64x60_clr_bits(&bh, MV64x60_TIMR_CNTR_0_3_CNTL, + ((1<<0) | (1<<8) | (1<<16) | (1<<24))); + mv64x60_clr_bits(&bh, GT64260_TIMR_CNTR_4_7_CNTL, + ((1<<0) | (1<<8) | (1<<16) | (1<<24))); + + /* + * Set MPSC Multiplex RMII + * NOTE: ethernet driver modifies bit 0 and 1 + */ + mv64x60_write(&bh, GT64260_MPP_SERIAL_PORTS_MULTIPLEX, 0x00001102); + + /* + * The EV-64260-BP uses several Multi-Purpose Pins (MPP) on the 64260 + * bridge as interrupt inputs (via the General Purpose Ports (GPP) + * register). Need to route the MPP inputs to the GPP and set the + * polarity correctly. + * + * In MPP Control 2 Register + * MPP 21 -> GPP 21 (DUART channel A intr) bits 20-23 -> 0 + * MPP 22 -> GPP 22 (DUART channel B intr) bits 24-27 -> 0 + */ + mv64x60_clr_bits(&bh, MV64x60_MPP_CNTL_2, (0xf<<20) | (0xf<<24) ); + + /* + * In MPP Control 3 Register + * MPP 26 -> GPP 26 (RTC INT) bits 8-11 -> 0 + * MPP 27 -> GPP 27 (PCI 0 INTA) bits 12-15 -> 0 + * MPP 29 -> GPP 29 (PCI 1 INTA) bits 20-23 -> 0 + */ + mv64x60_clr_bits(&bh, MV64x60_MPP_CNTL_3, (0xf<<8)|(0xf<<12)|(0xf<<20)); + +#define GPP_EXTERNAL_INTERRUPTS \ + ((1<<21) | (1<<22) | (1<<26) | (1<<27) | (1<<29)) + /* DUART & PCI interrupts are inputs */ + mv64x60_clr_bits(&bh, MV64x60_GPP_IO_CNTL, GPP_EXTERNAL_INTERRUPTS); + /* DUART & PCI interrupts are active low */ + mv64x60_set_bits(&bh, MV64x60_GPP_LEVEL_CNTL, GPP_EXTERNAL_INTERRUPTS); + + /* Clear any pending interrupts for these inputs and enable them. */ + mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, ~GPP_EXTERNAL_INTERRUPTS); + mv64x60_set_bits(&bh, MV64x60_GPP_INTR_MASK, GPP_EXTERNAL_INTERRUPTS); + + return; +} + +static void __init +ev64260_setup_bridge(void) +{ + struct mv64x60_setup_info si; + int i; + + memset(&si, 0, sizeof(si)); + + si.phys_reg_base = CONFIG_MV64X60_NEW_BASE; + + si.pci_0.enable_bus = 1; + si.pci_0.pci_io.cpu_base = EV64260_PCI0_IO_CPU_BASE; + si.pci_0.pci_io.pci_base_hi = 0; + si.pci_0.pci_io.pci_base_lo = EV64260_PCI0_IO_PCI_BASE; + si.pci_0.pci_io.size = EV64260_PCI0_IO_SIZE; + si.pci_0.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE; + si.pci_0.pci_mem[0].cpu_base = EV64260_PCI0_MEM_CPU_BASE; + si.pci_0.pci_mem[0].pci_base_hi = 0; + si.pci_0.pci_mem[0].pci_base_lo = EV64260_PCI0_MEM_PCI_BASE; + si.pci_0.pci_mem[0].size = EV64260_PCI0_MEM_SIZE; + si.pci_0.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE; + si.pci_0.pci_cmd_bits = 0; + si.pci_0.latency_timer = 0x8; + + si.pci_1.enable_bus = 1; + si.pci_1.pci_io.cpu_base = EV64260_PCI1_IO_CPU_BASE; + si.pci_1.pci_io.pci_base_hi = 0; + si.pci_1.pci_io.pci_base_lo = EV64260_PCI1_IO_PCI_BASE; + si.pci_1.pci_io.size = EV64260_PCI1_IO_SIZE; + si.pci_1.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE; + si.pci_1.pci_mem[0].cpu_base = EV64260_PCI1_MEM_CPU_BASE; + si.pci_1.pci_mem[0].pci_base_hi = 0; + si.pci_1.pci_mem[0].pci_base_lo = EV64260_PCI1_MEM_PCI_BASE; + si.pci_1.pci_mem[0].size = EV64260_PCI1_MEM_SIZE; + si.pci_1.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE; + si.pci_1.pci_cmd_bits = 0; + si.pci_1.latency_timer = 0x8; + + for (i=0; i<MV64x60_CPU2MEM_WINDOWS; i++) { + si.cpu_prot_options[i] = 0; + si.cpu_snoop_options[i] = GT64260_CPU_SNOOP_WB; + si.pci_0.acc_cntl_options[i] = + GT64260_PCI_ACC_CNTL_DREADEN | + GT64260_PCI_ACC_CNTL_RDPREFETCH | + GT64260_PCI_ACC_CNTL_RDLINEPREFETCH | + GT64260_PCI_ACC_CNTL_RDMULPREFETCH | + GT64260_PCI_ACC_CNTL_SWAP_NONE | + GT64260_PCI_ACC_CNTL_MBURST_32_BTYES; + si.pci_0.snoop_options[i] = GT64260_PCI_SNOOP_WB; + si.pci_1.acc_cntl_options[i] = + GT64260_PCI_ACC_CNTL_DREADEN | + GT64260_PCI_ACC_CNTL_RDPREFETCH | + GT64260_PCI_ACC_CNTL_RDLINEPREFETCH | + GT64260_PCI_ACC_CNTL_RDMULPREFETCH | + GT64260_PCI_ACC_CNTL_SWAP_NONE | + GT64260_PCI_ACC_CNTL_MBURST_32_BTYES; + si.pci_1.snoop_options[i] = GT64260_PCI_SNOOP_WB; + } + + /* Lookup PCI host bridges */ + if (mv64x60_init(&bh, &si)) + printk(KERN_ERR "Bridge initialization failed.\n"); + + pci_dram_offset = 0; /* System mem at same addr on PCI & cpu bus */ + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = ev64260_map_irq; + ppc_md.pci_exclude_device = mv64x60_pci_exclude_device; + + mv64x60_set_bus(&bh, 0, 0); + bh.hose_a->first_busno = 0; + bh.hose_a->last_busno = 0xff; + bh.hose_a->last_busno = pciauto_bus_scan(bh.hose_a, 0); + + bh.hose_b->first_busno = bh.hose_a->last_busno + 1; + mv64x60_set_bus(&bh, 1, bh.hose_b->first_busno); + bh.hose_b->last_busno = 0xff; + bh.hose_b->last_busno = pciauto_bus_scan(bh.hose_b, + bh.hose_b->first_busno); + + return; +} + +#if defined(CONFIG_SERIAL_8250) && !defined(CONFIG_SERIAL_MPSC_CONSOLE) +static void __init +ev64260_early_serial_map(void) +{ + struct uart_port port; + static char first_time = 1; + + if (first_time) { + memset(&port, 0, sizeof(port)); + + port.membase = ioremap(EV64260_SERIAL_0, EV64260_UART_SIZE); + port.irq = EV64260_UART_0_IRQ; + port.uartclk = BASE_BAUD * 16; + port.regshift = 2; + port.iotype = SERIAL_IO_MEM; + port.flags = STD_COM_FLAGS; + +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) + gen550_init(0, &port); +#endif + + if (early_serial_setup(&port) != 0) + printk(KERN_WARNING "Early serial init of port 0" + "failed\n"); + + first_time = 0; + } + + return; +} +#elif defined(CONFIG_SERIAL_MPSC_CONSOLE) +static void __init +ev64260_early_serial_map(void) +{ +} +#endif + +static void __init +ev64260_setup_arch(void) +{ + if (ppc_md.progress) + ppc_md.progress("ev64260_setup_arch: enter", 0); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_SDA2; +#endif + + if (ppc_md.progress) + ppc_md.progress("ev64260_setup_arch: Enabling L2 cache", 0); + + /* Enable L2 and L3 caches (if 745x) */ + _set_L2CR(_get_L2CR() | L2CR_L2E); + _set_L3CR(_get_L3CR() | L3CR_L3E); + + if (ppc_md.progress) + ppc_md.progress("ev64260_setup_arch: Initializing bridge", 0); + + ev64260_setup_bridge(); /* set up PCI bridge(s) */ + ev64260_setup_peripherals(); /* set up chip selects/GPP/MPP etc */ + + if (ppc_md.progress) + ppc_md.progress("ev64260_setup_arch: bridge init complete", 0); + +#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_MPSC_CONSOLE) + ev64260_early_serial_map(); +#endif + + printk(KERN_INFO "%s %s port (C) 2001 MontaVista Software, Inc." + "(source@mvista.com)\n", BOARD_VENDOR, BOARD_MACHINE); + + if (ppc_md.progress) + ppc_md.progress("ev64260_setup_arch: exit", 0); + + return; +} + +/* Platform device data fixup routines. */ +#if defined(CONFIG_SERIAL_MPSC) +static void __init +ev64260_fixup_mpsc_pdata(struct platform_device *pdev) +{ + struct mpsc_pdata *pdata; + + pdata = (struct mpsc_pdata *)pdev->dev.platform_data; + + pdata->max_idle = 40; + pdata->default_baud = EV64260_DEFAULT_BAUD; + pdata->brg_clk_src = EV64260_MPSC_CLK_SRC; + pdata->brg_clk_freq = EV64260_MPSC_CLK_FREQ; + + return; +} + +static int __init +ev64260_platform_notify(struct device *dev) +{ + static struct { + char *bus_id; + void ((*rtn)(struct platform_device *pdev)); + } dev_map[] = { + { MPSC_CTLR_NAME ".0", ev64260_fixup_mpsc_pdata }, + { MPSC_CTLR_NAME ".1", ev64260_fixup_mpsc_pdata }, + }; + struct platform_device *pdev; + int i; + + if (dev && dev->bus_id) + for (i=0; i<ARRAY_SIZE(dev_map); i++) + if (!strncmp(dev->bus_id, dev_map[i].bus_id, + BUS_ID_SIZE)) { + + pdev = container_of(dev, + struct platform_device, dev); + dev_map[i].rtn(pdev); + } + + return 0; +} +#endif + +static void +ev64260_reset_board(void *addr) +{ + local_irq_disable(); + + /* disable and invalidate the L2 cache */ + _set_L2CR(0); + _set_L2CR(0x200000); + + /* flush and disable L1 I/D cache */ + __asm__ __volatile__ + ("mfspr 3,1008\n\t" + "ori 5,5,0xcc00\n\t" + "ori 4,3,0xc00\n\t" + "andc 5,3,5\n\t" + "sync\n\t" + "mtspr 1008,4\n\t" + "isync\n\t" + "sync\n\t" + "mtspr 1008,5\n\t" + "isync\n\t" + "sync\n\t"); + + /* unmap any other random cs's that might overlap with bootcs */ + mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_0_WIN, 0, 0, 0); + bh.ci->disable_window_32bit(&bh, MV64x60_CPU2DEV_0_WIN); + mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN, 0, 0, 0); + bh.ci->disable_window_32bit(&bh, MV64x60_CPU2DEV_1_WIN); + mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_2_WIN, 0, 0, 0); + bh.ci->disable_window_32bit(&bh, MV64x60_CPU2DEV_2_WIN); + mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_3_WIN, 0, 0, 0); + bh.ci->disable_window_32bit(&bh, MV64x60_CPU2DEV_3_WIN); + + /* map bootrom back in to gt @ reset defaults */ + mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN, + 0xff800000, 8*1024*1024, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN); + + /* move reg base back to default, setup default pci0 */ + mv64x60_write(&bh, MV64x60_INTERNAL_SPACE_DECODE, + (1<<24) | CONFIG_MV64X60_BASE >> 20); + + /* NOTE: FROM NOW ON no more GT_REGS accesses.. 0x1 is not mapped + * via BAT or MMU, and MSR IR/DR is ON */ + /* SRR0 has system reset vector, SRR1 has default MSR value */ + /* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */ + /* NOTE: assumes reset vector is at 0xfff00100 */ + __asm__ __volatile__ + ("mtspr 26, %0\n\t" + "li 4,(1<<6)\n\t" + "mtspr 27,4\n\t" + "rfi\n\t" + :: "r" (addr):"r4"); + + return; +} + +static void +ev64260_restart(char *cmd) +{ + volatile ulong i = 10000000; + + ev64260_reset_board((void *)0xfff00100); + + while (i-- > 0); + panic("restart failed\n"); +} + +static void +ev64260_halt(void) +{ + local_irq_disable(); + while (1); + /* NOTREACHED */ +} + +static void +ev64260_power_off(void) +{ + ev64260_halt(); + /* NOTREACHED */ +} + +static int +ev64260_show_cpuinfo(struct seq_file *m) +{ + uint pvid; + + pvid = mfspr(SPRN_PVR); + seq_printf(m, "vendor\t\t: " BOARD_VENDOR "\n"); + seq_printf(m, "machine\t\t: " BOARD_MACHINE "\n"); + seq_printf(m, "cpu MHz\t\t: %d\n", ev64260_get_cpu_speed()/1000/1000); + seq_printf(m, "bus MHz\t\t: %d\n", ev64260_get_bus_speed()/1000/1000); + + return 0; +} + +/* DS1501 RTC has too much variation to use RTC for calibration */ +static void __init +ev64260_calibrate_decr(void) +{ + ulong freq; + + freq = ev64260_get_bus_speed()/4; + + printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n", + freq/1000000, freq%1000000); + + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); + + return; +} + +/* + * Set BAT 3 to map 0xfb000000 to 0xfc000000 of physical memory space. + */ +static __inline__ void +ev64260_set_bat(void) +{ + mb(); + mtspr(SPRN_DBAT1U, 0xfb0001fe); + mtspr(SPRN_DBAT1L, 0xfb00002a); + mb(); + + return; +} + +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) +static void __init +ev64260_map_io(void) +{ + io_block_mapping(0xfb000000, 0xfb000000, 0x01000000, _PAGE_IO); +} +#endif + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ +#ifdef CONFIG_BLK_DEV_INITRD + extern int initrd_below_start_ok; + + initrd_start=initrd_end=0; + initrd_below_start_ok=0; +#endif /* CONFIG_BLK_DEV_INITRD */ + + parse_bootinfo(find_bootinfo()); + + isa_mem_base = 0; + isa_io_base = EV64260_PCI0_IO_CPU_BASE; + pci_dram_offset = EV64260_PCI0_MEM_CPU_BASE; + + loops_per_jiffy = ev64260_get_cpu_speed() / HZ; + + ppc_md.setup_arch = ev64260_setup_arch; + ppc_md.show_cpuinfo = ev64260_show_cpuinfo; + ppc_md.init_IRQ = gt64260_init_irq; + ppc_md.get_irq = gt64260_get_irq; + + ppc_md.restart = ev64260_restart; + ppc_md.power_off = ev64260_power_off; + ppc_md.halt = ev64260_halt; + + ppc_md.find_end_of_memory = ev64260_find_end_of_memory; + + ppc_md.init = NULL; + + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; + ppc_md.calibrate_decr = ev64260_calibrate_decr; + + bh.p_base = CONFIG_MV64X60_NEW_BASE; + + ev64260_set_bat(); + +#ifdef CONFIG_SERIAL_8250 +#if defined(CONFIG_SERIAL_TEXT_DEBUG) + ppc_md.setup_io_mappings = ev64260_map_io; + ppc_md.progress = gen550_progress; +#endif +#if defined(CONFIG_KGDB) + ppc_md.setup_io_mappings = ev64260_map_io; + ppc_md.early_serial_map = ev64260_early_serial_map; +#endif +#elif defined(CONFIG_SERIAL_MPSC_CONSOLE) +#ifdef CONFIG_SERIAL_TEXT_DEBUG + ppc_md.setup_io_mappings = ev64260_map_io; + ppc_md.progress = mv64x60_mpsc_progress; + mv64x60_progress_init(CONFIG_MV64X60_NEW_BASE); +#endif /* CONFIG_SERIAL_TEXT_DEBUG */ +#ifdef CONFIG_KGDB + ppc_md.setup_io_mappings = ev64260_map_io; + ppc_md.early_serial_map = ev64260_early_serial_map; +#endif /* CONFIG_KGDB */ + +#endif + +#if defined(CONFIG_SERIAL_MPSC) + platform_notify = ev64260_platform_notify; +#endif + + return; +} diff --git a/arch/ppc/platforms/ev64260.h b/arch/ppc/platforms/ev64260.h new file mode 100644 index 00000000000..bedffced3a0 --- /dev/null +++ b/arch/ppc/platforms/ev64260.h @@ -0,0 +1,128 @@ +/* + * arch/ppc/platforms/ev64260.h + * + * Definitions for Marvell/Galileo EV-64260-BP Evaluation Board. + * + * Author: Mark A. Greer <mgreer@mvista.com> + * + * 2001-2002 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +/* + * The MV64x60 has 2 PCI buses each with 1 window from the CPU bus to + * PCI I/O space and 4 windows from the CPU bus to PCI MEM space. + * We'll only use one PCI MEM window on each PCI bus. + * + * This is the CPU physical memory map (windows must be at least 1MB and start + * on a boundary that is a multiple of the window size): + * + * 0xfc000000-0xffffffff - External FLASH on device module + * 0xfbf00000-0xfbffffff - Embedded (on board) FLASH + * 0xfbe00000-0xfbefffff - GT64260 Registers (preferably) + * but really a config option + * 0xfbd00000-0xfbdfffff - External SRAM on device module + * 0xfbc00000-0xfbcfffff - TODC chip on device module + * 0xfbb00000-0xfbbfffff - External UART on device module + * 0xa2000000-0xfbafffff - <hole> + * 0xa1000000-0xa1ffffff - PCI 1 I/O (defined in gt64260.h) + * 0xa0000000-0xa0ffffff - PCI 0 I/O (defined in gt64260.h) + * 0x90000000-0x9fffffff - PCI 1 MEM (defined in gt64260.h) + * 0x80000000-0x8fffffff - PCI 0 MEM (defined in gt64260.h) + */ + +#ifndef __PPC_PLATFORMS_EV64260_H +#define __PPC_PLATFORMS_EV64260_H + +/* PCI mappings */ +#define EV64260_PCI0_IO_CPU_BASE 0xa0000000 +#define EV64260_PCI0_IO_PCI_BASE 0x00000000 +#define EV64260_PCI0_IO_SIZE 0x01000000 + +#define EV64260_PCI0_MEM_CPU_BASE 0x80000000 +#define EV64260_PCI0_MEM_PCI_BASE 0x80000000 +#define EV64260_PCI0_MEM_SIZE 0x10000000 + +#define EV64260_PCI1_IO_CPU_BASE (EV64260_PCI0_IO_CPU_BASE + \ + EV64260_PCI0_IO_SIZE) +#define EV64260_PCI1_IO_PCI_BASE (EV64260_PCI0_IO_PCI_BASE + \ + EV64260_PCI0_IO_SIZE) +#define EV64260_PCI1_IO_SIZE 0x01000000 + +#define EV64260_PCI1_MEM_CPU_BASE (EV64260_PCI0_MEM_CPU_BASE + \ + EV64260_PCI0_MEM_SIZE) +#define EV64260_PCI1_MEM_PCI_BASE (EV64260_PCI0_MEM_PCI_BASE + \ + EV64260_PCI0_MEM_SIZE) +#define EV64260_PCI1_MEM_SIZE 0x10000000 + +/* CPU Physical Memory Map setup (other than PCI) */ +#define EV64260_EXT_FLASH_BASE 0xfc000000 +#define EV64260_EMB_FLASH_BASE 0xfbf00000 +#define EV64260_EXT_SRAM_BASE 0xfbd00000 +#define EV64260_TODC_BASE 0xfbc00000 +#define EV64260_UART_BASE 0xfbb00000 + +#define EV64260_EXT_FLASH_SIZE_ACTUAL 0x04000000 /* <= 64MB Extern FLASH */ +#define EV64260_EMB_FLASH_SIZE_ACTUAL 0x00080000 /* 512KB of Embed FLASH */ +#define EV64260_EXT_SRAM_SIZE_ACTUAL 0x00100000 /* 1MB SDRAM */ +#define EV64260_TODC_SIZE_ACTUAL 0x00000020 /* 32 bytes for TODC */ +#define EV64260_UART_SIZE_ACTUAL 0x00000040 /* 64 bytes for DUART */ + +#define EV64260_EXT_FLASH_SIZE max(GT64260_WINDOW_SIZE_MIN, \ + EV64260_EXT_FLASH_SIZE_ACTUAL) +#define EV64260_EMB_FLASH_SIZE max(GT64260_WINDOW_SIZE_MIN, \ + EV64260_EMB_FLASH_SIZE_ACTUAL) +#define EV64260_EXT_SRAM_SIZE max(GT64260_WINDOW_SIZE_MIN, \ + EV64260_EXT_SRAM_SIZE_ACTUAL) +#define EV64260_TODC_SIZE max(GT64260_WINDOW_SIZE_MIN, \ + EV64260_TODC_SIZE_ACTUAL) +/* Assembler in bootwrapper blows up if 'max' is used */ +#define EV64260_UART_SIZE GT64260_WINDOW_SIZE_MIN +#define EV64260_UART_END ((EV64260_UART_BASE + \ + EV64260_UART_SIZE - 1) & 0xfff00000) + +/* Board-specific IRQ info */ +#define EV64260_UART_0_IRQ 85 +#define EV64260_UART_1_IRQ 86 +#define EV64260_PCI_0_IRQ 91 +#define EV64260_PCI_1_IRQ 93 + +/* Serial port setup */ +#define EV64260_DEFAULT_BAUD 115200 + +#if defined(CONFIG_SERIAL_MPSC_CONSOLE) +#define SERIAL_PORT_DFNS + +#define EV64260_MPSC_CLK_SRC 8 /* TCLK */ +#define EV64260_MPSC_CLK_FREQ 100000000 /* 100MHz clk */ +#else +#define EV64260_SERIAL_0 (EV64260_UART_BASE + 0x20) +#define EV64260_SERIAL_1 EV64260_UART_BASE + +#define BASE_BAUD (EV64260_DEFAULT_BAUD * 2) + +#ifdef CONFIG_SERIAL_MANY_PORTS +#define RS_TABLE_SIZE 64 +#else +#define RS_TABLE_SIZE 2 +#endif + +#ifdef CONFIG_SERIAL_DETECT_IRQ +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ) +#else +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST) +#endif + +/* Required for bootloader's ns16550.c code */ +#define STD_SERIAL_PORT_DFNS \ + { 0, BASE_BAUD, EV64260_SERIAL_0, EV64260_UART_0_IRQ, STD_COM_FLAGS, \ + iomem_base: (u8 *)EV64260_SERIAL_0, /* ttyS0 */ \ + iomem_reg_shift: 2, \ + io_type: SERIAL_IO_MEM }, + +#define SERIAL_PORT_DFNS \ + STD_SERIAL_PORT_DFNS +#endif +#endif /* __PPC_PLATFORMS_EV64260_H */ diff --git a/arch/ppc/platforms/fads.h b/arch/ppc/platforms/fads.h new file mode 100644 index 00000000000..632b8178ce6 --- /dev/null +++ b/arch/ppc/platforms/fads.h @@ -0,0 +1,57 @@ +/* + * A collection of structures, addresses, and values associated with + * the Motorola 860T FADS board. Copied from the MBX stuff. + * + * Copyright (c) 1998 Dan Malek (dmalek@jlc.net) + */ +#ifdef __KERNEL__ +#ifndef __ASM_FADS_H__ +#define __ASM_FADS_H__ + +#include <linux/config.h> + +#include <asm/ppcboot.h> + +/* Memory map is configured by the PROM startup. + * I tried to follow the FADS manual, although the startup PROM + * dictates this and we simply have to move some of the physical + * addresses for Linux. + */ +#define BCSR_ADDR ((uint)0xff010000) +#define BCSR_SIZE ((uint)(64 * 1024)) +#define BCSR0 ((uint)0xff010000) +#define BCSR1 ((uint)0xff010004) +#define BCSR2 ((uint)0xff010008) +#define BCSR3 ((uint)0xff01000c) +#define BCSR4 ((uint)0xff010010) + +#define IMAP_ADDR ((uint)0xff000000) +#define IMAP_SIZE ((uint)(64 * 1024)) + +#define PCMCIA_MEM_ADDR ((uint)0xff020000) +#define PCMCIA_MEM_SIZE ((uint)(64 * 1024)) + +/* Bits of interest in the BCSRs. + */ +#define BCSR1_ETHEN ((uint)0x20000000) +#define BCSR1_RS232EN_1 ((uint)0x01000000) +#define BCSR1_RS232EN_2 ((uint)0x00040000) +#define BCSR4_ETHLOOP ((uint)0x80000000) /* EEST Loopback */ +#define BCSR4_EEFDX ((uint)0x40000000) /* EEST FDX enable */ +#define BCSR4_FETH_EN ((uint)0x08000000) /* PHY enable */ +#define BCSR4_FETHCFG0 ((uint)0x04000000) /* PHY autoneg mode */ +#define BCSR4_FETHCFG1 ((uint)0x00400000) /* PHY autoneg mode */ +#define BCSR4_FETHFDE ((uint)0x02000000) /* PHY FDX advertise */ +#define BCSR4_FETHRST ((uint)0x00200000) /* PHY Reset */ + +/* Interrupt level assignments. + */ +#define FEC_INTERRUPT SIU_LEVEL1 /* FEC interrupt */ +#define PHY_INTERRUPT SIU_IRQ2 /* PHY link change interrupt */ + +/* We don't use the 8259. + */ +#define NR_8259_INTS 0 + +#endif /* __ASM_FADS_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/gemini.h b/arch/ppc/platforms/gemini.h new file mode 100644 index 00000000000..06de5924891 --- /dev/null +++ b/arch/ppc/platforms/gemini.h @@ -0,0 +1,168 @@ +/* + * arch/ppc/platforms/gemini.h + * + * + * Onboard registers and descriptions for Synergy Microsystems' + * "Gemini" boards. + * + */ +#ifdef __KERNEL__ +#ifndef __PPC_GEMINI_H +#define __PPC_GEMINI_H + +/* Registers */ + +#define GEMINI_SERIAL_B (0xffeffb00) +#define GEMINI_SERIAL_A (0xffeffb08) +#define GEMINI_USWITCH (0xffeffd00) +#define GEMINI_BREV (0xffeffe00) +#define GEMINI_BECO (0xffeffe08) +#define GEMINI_FEAT (0xffeffe10) +#define GEMINI_BSTAT (0xffeffe18) +#define GEMINI_CPUSTAT (0xffeffe20) +#define GEMINI_L2CFG (0xffeffe30) +#define GEMINI_MEMCFG (0xffeffe38) +#define GEMINI_FLROM (0xffeffe40) +#define GEMINI_P0PCI (0xffeffe48) +#define GEMINI_FLWIN (0xffeffe50) +#define GEMINI_P0INTMASK (0xffeffe60) +#define GEMINI_P0INTAP (0xffeffe68) +#define GEMINI_PCIERR (0xffeffe70) +#define GEMINI_LEDBASE (0xffeffe80) +#define GEMINI_RTC (0xffe9fff8) +#define GEMINI_LEDS 8 +#define GEMINI_SWITCHES 8 + + +/* Flash ROM bit definitions */ +#define GEMINI_FLS_WEN (1<<0) +#define GEMINI_FLS_JMP (1<<6) +#define GEMINI_FLS_BOOT (1<<7) + +/* Memory bit definitions */ +#define GEMINI_MEM_TYPE_MASK 0xc0 +#define GEMINI_MEM_SIZE_MASK 0x38 +#define GEMINI_MEM_BANK_MASK 0x07 + +/* L2 cache bit definitions */ +#define GEMINI_L2_SIZE_MASK 0xc0 +#define GEMINI_L2_RATIO_MASK 0x03 + +/* Timebase register bit definitons */ +#define GEMINI_TIMEB0_EN (1<<0) +#define GEMINI_TIMEB1_EN (1<<1) +#define GEMINI_TIMEB2_EN (1<<2) +#define GEMINI_TIMEB3_EN (1<<3) + +/* CPU status bit definitions */ +#define GEMINI_CPU_ID_MASK 0x03 +#define GEMINI_CPU_COUNT_MASK 0x0c +#define GEMINI_CPU0_HALTED (1<<4) +#define GEMINI_CPU1_HALTED (1<<5) +#define GEMINI_CPU2_HALTED (1<<6) +#define GEMINI_CPU3_HALTED (1<<7) + +/* Board status bit definitions */ +#define GEMINI_BRD_FAIL (1<<0) /* FAIL led is lit */ +#define GEMINI_BRD_BUS_MASK 0x0c /* PowerPC bus speed */ + +/* Board family/feature bit descriptions */ +#define GEMINI_FEAT_HAS_FLASH (1<<0) +#define GEMINI_FEAT_HAS_ETH (1<<1) +#define GEMINI_FEAT_HAS_SCSI (1<<2) +#define GEMINI_FEAT_HAS_P0 (1<<3) +#define GEMINI_FEAT_FAM_MASK 0xf0 + +/* Mod/ECO bit definitions */ +#define GEMINI_ECO_LEVEL_MASK 0x0f +#define GEMINI_MOD_MASK 0xf0 + +/* Type/revision bit definitions */ +#define GEMINI_REV_MASK 0x0f +#define GEMINI_TYPE_MASK 0xf0 + +/* User switch definitions */ +#define GEMINI_SWITCH_VERBOSE 1 /* adds "debug" to boot cmd line */ +#define GEMINI_SWITCH_SINGLE_USER 7 /* boots into "single-user" mode */ + +#define SGS_RTC_CONTROL 0 +#define SGS_RTC_SECONDS 1 +#define SGS_RTC_MINUTES 2 +#define SGS_RTC_HOURS 3 +#define SGS_RTC_DAY 4 +#define SGS_RTC_DAY_OF_MONTH 5 +#define SGS_RTC_MONTH 6 +#define SGS_RTC_YEAR 7 + +#define SGS_RTC_SET 0x80 +#define SGS_RTC_IS_STOPPED 0x80 + +#define GRACKLE_CONFIG_ADDR_ADDR (0xfec00000) +#define GRACKLE_CONFIG_DATA_ADDR (0xfee00000) + +#define GEMINI_BOOT_INIT (0xfff00100) + +#ifndef __ASSEMBLY__ + +static inline void grackle_write( unsigned long addr, unsigned long data ) +{ + __asm__ __volatile__( + " stwbrx %1, 0, %0\n \ + sync\n \ + stwbrx %3, 0, %2\n \ + sync " + : /* no output */ + : "r" (GRACKLE_CONFIG_ADDR_ADDR), "r" (addr), + "r" (GRACKLE_CONFIG_DATA_ADDR), "r" (data)); +} + +static inline unsigned long grackle_read( unsigned long addr ) +{ + unsigned long val; + + __asm__ __volatile__( + " stwbrx %1, 0, %2\n \ + sync\n \ + lwbrx %0, 0, %3\n \ + sync " + : "=r" (val) + : "r" (addr), "r" (GRACKLE_CONFIG_ADDR_ADDR), + "r" (GRACKLE_CONFIG_DATA_ADDR)); + + return val; +} + +static inline void gemini_led_on( int led ) +{ + if (led >= 0 && led < GEMINI_LEDS) + *(unsigned char *)(GEMINI_LEDBASE + (led<<3)) = 1; +} + +static inline void gemini_led_off(int led) +{ + if (led >= 0 && led < GEMINI_LEDS) + *(unsigned char *)(GEMINI_LEDBASE + (led<<3)) = 0; +} + +static inline int gemini_led_val(int led) +{ + int val = 0; + if (led >= 0 && led < GEMINI_LEDS) + val = *(unsigned char *)(GEMINI_LEDBASE + (led<<3)); + return (val & 0x1); +} + +/* returns processor id from the board */ +static inline int gemini_processor(void) +{ + unsigned char cpu = *(unsigned char *)(GEMINI_CPUSTAT); + return (int) ((cpu == 0) ? 4 : (cpu & GEMINI_CPU_ID_MASK)); +} + + +extern void _gemini_reboot(void); +extern void gemini_prom_init(void); +extern void gemini_init_l2(void); +#endif /* __ASSEMBLY__ */ +#endif +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/gemini_pci.c b/arch/ppc/platforms/gemini_pci.c new file mode 100644 index 00000000000..95656091ba2 --- /dev/null +++ b/arch/ppc/platforms/gemini_pci.c @@ -0,0 +1,41 @@ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/slab.h> + +#include <asm/machdep.h> +#include <platforms/gemini.h> +#include <asm/byteorder.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/pci-bridge.h> + +void __init gemini_pcibios_fixup(void) +{ + int i; + struct pci_dev *dev = NULL; + + for_each_pci_dev(dev) { + for(i = 0; i < 6; i++) { + if (dev->resource[i].flags & IORESOURCE_IO) { + dev->resource[i].start |= (0xfe << 24); + dev->resource[i].end |= (0xfe << 24); + } + } + } +} + + +/* The "bootloader" for Synergy boards does none of this for us, so we need to + lay it all out ourselves... --Dan */ +void __init gemini_find_bridges(void) +{ + struct pci_controller* hose; + + ppc_md.pcibios_fixup = gemini_pcibios_fixup; + + hose = pcibios_alloc_controller(); + if (!hose) + return; + setup_indirect_pci(hose, 0xfec00000, 0xfee00000); +} diff --git a/arch/ppc/platforms/gemini_prom.S b/arch/ppc/platforms/gemini_prom.S new file mode 100644 index 00000000000..8c5065d5650 --- /dev/null +++ b/arch/ppc/platforms/gemini_prom.S @@ -0,0 +1,93 @@ +/* + * arch/ppc/platforms/gemini_prom.S + * + * Not really prom support code (yet), but sort of anti-prom code. The current + * bootloader does a number of things it shouldn't and doesn't do things that it + * should. The stuff in here is mainly a hodge-podge collection of setup code + * to get the board up and running. + * ---Dan + */ + +#include <linux/config.h> +#include <asm/reg.h> +#include <asm/page.h> +#include <platforms/gemini.h> +#include <asm/ppc_asm.h> + +/* + * On 750's the MMU is on when Linux is booted, so we need to clear out the + * bootloader's BAT settings, make sure we're in supervisor state (gotcha!), + * and turn off the MMU. + * + */ + +_GLOBAL(gemini_prom_init) +#ifdef CONFIG_SMP + /* Since the MMU's on, get stuff in rom space that we'll need */ + lis r4,GEMINI_CPUSTAT@h + ori r4,r4,GEMINI_CPUSTAT@l + lbz r5,0(r4) + andi. r5,r5,3 + mr r24,r5 /* cpu # used later on */ +#endif + mfmsr r4 + li r3,MSR_PR /* ensure supervisor! */ + ori r3,r3,MSR_IR|MSR_DR + andc r4,r4,r3 + mtmsr r4 + isync +#if 0 + /* zero out the bats now that the MMU is off */ +prom_no_mmu: + li r3,0 + mtspr SPRN_IBAT0U,r3 + mtspr SPRN_IBAT0L,r3 + mtspr SPRN_IBAT1U,r3 + mtspr SPRN_IBAT1L,r3 + mtspr SPRN_IBAT2U,r3 + mtspr SPRN_IBAT2L,r3 + mtspr SPRN_IBAT3U,r3 + mtspr SPRN_IBAT3L,r3 + + mtspr SPRN_DBAT0U,r3 + mtspr SPRN_DBAT0L,r3 + mtspr SPRN_DBAT1U,r3 + mtspr SPRN_DBAT1L,r3 + mtspr SPRN_DBAT2U,r3 + mtspr SPRN_DBAT2L,r3 + mtspr SPRN_DBAT3U,r3 + mtspr SPRN_DBAT3L,r3 +#endif + + /* the bootloader (as far as I'm currently aware) doesn't mess with page + tables, but since we're already here, might as well zap these, too */ + li r4,0 + mtspr SPRN_SDR1,r4 + + li r4,16 + mtctr r4 + li r3,0 + li r4,0 +3: mtsrin r3,r4 + addi r3,r3,1 + bdnz 3b + +#ifdef CONFIG_SMP + /* The 750 book (and Mot/IBM support) says that this will "assist" snooping + when in SMP. Not sure yet whether this should stay or leave... */ + mfspr r4,SPRN_HID0 + ori r4,r4,HID0_ABE + mtspr SPRN_HID0,r4 + sync +#endif /* CONFIG_SMP */ + blr + +/* apparently, SMon doesn't pay attention to HID0[SRST]. Disable the MMU and + branch to 0xfff00100 */ +_GLOBAL(_gemini_reboot) + lis r5,GEMINI_BOOT_INIT@h + ori r5,r5,GEMINI_BOOT_INIT@l + li r6,MSR_IP + mtspr SPRN_SRR0,r5 + mtspr SPRN_SRR1,r6 + rfi diff --git a/arch/ppc/platforms/gemini_serial.h b/arch/ppc/platforms/gemini_serial.h new file mode 100644 index 00000000000..69855aeec88 --- /dev/null +++ b/arch/ppc/platforms/gemini_serial.h @@ -0,0 +1,41 @@ +#ifdef __KERNEL__ +#ifndef __ASMPPC_GEMINI_SERIAL_H +#define __ASMPPC_GEMINI_SERIAL_H + +#include <linux/config.h> +#include <platforms/gemini.h> + +#ifdef CONFIG_SERIAL_MANY_PORTS +#define RS_TABLE_SIZE 64 +#else +#define RS_TABLE_SIZE 4 +#endif + +/* Rate for the 24.576 Mhz clock for the onboard serial chip */ +#define BASE_BAUD (24576000 / 16) + +#ifdef CONFIG_SERIAL_DETECT_IRQ +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ) +#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ) +#else +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST) +#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF) +#endif + +#define STD_SERIAL_PORT_DEFNS \ + { 0, BASE_BAUD, GEMINI_SERIAL_A, 15, STD_COM_FLAGS }, /* ttyS0 */ \ + { 0, BASE_BAUD, GEMINI_SERIAL_B, 14, STD_COM_FLAGS }, /* ttyS1 */ \ + +#ifdef CONFIG_GEMINI_PU32 +#define PU32_SERIAL_PORT_DEFNS \ + { 0, BASE_BAUD, NULL, 0, STD_COM_FLAGS }, +#else +#define PU32_SERIAL_PORT_DEFNS +#endif + +#define SERIAL_PORT_DFNS \ + STD_SERIAL_PORT_DEFNS \ + PU32_SERIAL_PORT_DEFNS + +#endif +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/gemini_setup.c b/arch/ppc/platforms/gemini_setup.c new file mode 100644 index 00000000000..1a42cb9b113 --- /dev/null +++ b/arch/ppc/platforms/gemini_setup.c @@ -0,0 +1,584 @@ +/* + * arch/ppc/platforms/gemini_setup.c + * + * Copyright (C) 1995 Linus Torvalds + * Adapted from 'alpha' version by Gary Thomas + * Modified by Cort Dougan (cort@cs.nmt.edu) + * Synergy Microsystems board support by Dan Cox (dan@synergymicro.com) + * + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/pci.h> +#include <linux/time.h> +#include <linux/kdev_t.h> +#include <linux/types.h> +#include <linux/major.h> +#include <linux/initrd.h> +#include <linux/console.h> +#include <linux/irq.h> +#include <linux/seq_file.h> +#include <linux/root_dev.h> +#include <linux/bcd.h> + +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/m48t35.h> +#include <platforms/gemini.h> +#include <asm/time.h> +#include <asm/open_pic.h> +#include <asm/bootinfo.h> + +void gemini_find_bridges(void); +static int gemini_get_clock_speed(void); +extern void gemini_pcibios_fixup(void); + +static char *gemini_board_families[] = { + "VGM", "VSS", "KGM", "VGR", "VCM", "VCS", "KCM", "VCR" +}; +static int gemini_board_count = sizeof(gemini_board_families) / + sizeof(gemini_board_families[0]); + +static unsigned int cpu_7xx[16] = { + 0, 15, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0 +}; +static unsigned int cpu_6xx[16] = { + 0, 0, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 0, 12, 7, 0 +}; + +/* + * prom_init is the Gemini version of prom.c:prom_init. We only need + * the BSS clearing code, so I copied that out of prom.c. This is a + * lot simpler than hacking prom.c so it will build with Gemini. -VAL + */ + +#define PTRRELOC(x) ((typeof(x))((unsigned long)(x) + offset)) + +unsigned long +prom_init(void) +{ + unsigned long offset = reloc_offset(); + unsigned long phys; + extern char __bss_start, _end; + + /* First zero the BSS -- use memset, some arches don't have + * caches on yet */ + memset_io(PTRRELOC(&__bss_start),0 , &_end - &__bss_start); + + /* Default */ + phys = offset + KERNELBASE; + + gemini_prom_init(); + + return phys; +} + +int +gemini_show_cpuinfo(struct seq_file *m) +{ + unsigned char reg, rev; + char *family; + unsigned int type; + + reg = readb(GEMINI_FEAT); + family = gemini_board_families[((reg>>4) & 0xf)]; + if (((reg>>4) & 0xf) > gemini_board_count) + printk(KERN_ERR "cpuinfo(): unable to determine board family\n"); + + reg = readb(GEMINI_BREV); + type = (reg>>4) & 0xf; + rev = reg & 0xf; + + reg = readb(GEMINI_BECO); + + seq_printf(m, "machine\t\t: Gemini %s%d, rev %c, eco %d\n", + family, type, (rev + 'A'), (reg & 0xf)); + + seq_printf(m, "board\t\t: Gemini %s", family); + if (type > 9) + seq_printf(m, "%c", (type - 10) + 'A'); + else + seq_printf(m, "%d", type); + + seq_printf(m, ", rev %c, eco %d\n", (rev + 'A'), (reg & 0xf)); + + seq_printf(m, "clock\t\t: %dMhz\n", gemini_get_clock_speed()); + + return 0; +} + +static u_char gemini_openpic_initsenses[] = { + 1, + 1, + 1, + 1, + 0, + 0, + 1, /* remainder are level-triggered */ +}; + +#define GEMINI_MPIC_ADDR (0xfcfc0000) +#define GEMINI_MPIC_PCI_CFG (0x80005800) + +void __init gemini_openpic_init(void) +{ + + OpenPIC_Addr = (volatile struct OpenPIC *) + grackle_read(GEMINI_MPIC_PCI_CFG + 0x10); + OpenPIC_InitSenses = gemini_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof( gemini_openpic_initsenses ); + + ioremap( GEMINI_MPIC_ADDR, OPENPIC_SIZE); +} + + +extern unsigned long loops_per_jiffy; +extern int root_mountflags; +extern char cmd_line[]; + +void +gemini_heartbeat(void) +{ + static unsigned long led = GEMINI_LEDBASE+(4*8); + static char direction = 8; + + + /* We only want to do this on 1 CPU */ + if (smp_processor_id()) + return; + *(char *)led = 0; + if ( (led + direction) > (GEMINI_LEDBASE+(7*8)) || + (led + direction) < (GEMINI_LEDBASE+(4*8)) ) + direction *= -1; + led += direction; + *(char *)led = 0xff; + ppc_md.heartbeat_count = ppc_md.heartbeat_reset; +} + +void __init gemini_setup_arch(void) +{ + extern char cmd_line[]; + + + loops_per_jiffy = 50000000/HZ; + +#ifdef CONFIG_BLK_DEV_INITRD + /* bootable off CDROM */ + if (initrd_start) + ROOT_DEV = Root_SR0; + else +#endif + ROOT_DEV = Root_SDA1; + + /* nothing but serial consoles... */ + sprintf(cmd_line, "%s console=ttyS0", cmd_line); + + printk("Boot arguments: %s\n", cmd_line); + + ppc_md.heartbeat = gemini_heartbeat; + ppc_md.heartbeat_reset = HZ/8; + ppc_md.heartbeat_count = 1; + + /* Lookup PCI hosts */ + gemini_find_bridges(); + /* take special pains to map the MPIC, since it isn't mapped yet */ + gemini_openpic_init(); + /* start the L2 */ + gemini_init_l2(); +} + + +int +gemini_get_clock_speed(void) +{ + unsigned long hid1, pvr; + int clock; + + pvr = mfspr(SPRN_PVR); + hid1 = (mfspr(SPRN_HID1) >> 28) & 0xf; + if (PVR_VER(pvr) == 8 || + PVR_VER(pvr) == 12) + hid1 = cpu_7xx[hid1]; + else + hid1 = cpu_6xx[hid1]; + + switch((readb(GEMINI_BSTAT) & 0xc) >> 2) { + + case 0: + default: + clock = (hid1*100)/3; + break; + + case 1: + clock = (hid1*125)/3; + break; + + case 2: + clock = (hid1*50); + break; + } + + return clock; +} + +void __init gemini_init_l2(void) +{ + unsigned char reg, brev, fam, creg; + unsigned long cache; + unsigned long pvr; + + reg = readb(GEMINI_L2CFG); + brev = readb(GEMINI_BREV); + fam = readb(GEMINI_FEAT); + pvr = mfspr(SPRN_PVR); + + switch(PVR_VER(pvr)) { + + case 8: + if (reg & 0xc0) + cache = (((reg >> 6) & 0x3) << 28); + else + cache = 0x3 << 28; + +#ifdef CONFIG_SMP + /* Pre-3.0 processor revs had snooping errata. Leave + their L2's disabled with SMP. -- Dan */ + if (PVR_CFG(pvr) < 3) { + printk("Pre-3.0 750; L2 left disabled!\n"); + return; + } +#endif /* CONFIG_SMP */ + + /* Special case: VGM5-B's came before L2 ratios were set on + the board. Processor speed shouldn't be too high, so + set L2 ratio to 1:1.5. */ + if ((brev == 0x51) && ((fam & 0xa0) >> 4) == 0) + reg |= 1; + + /* determine best cache ratio based upon what the board + tells us (which sometimes _may_ not be true) and + the processor speed. */ + else { + if (gemini_get_clock_speed() > 250) + reg = 2; + } + break; + case 12: + { + static unsigned long l2_size_val = 0; + + if (!l2_size_val) + l2_size_val = _get_L2CR(); + cache = l2_size_val; + break; + } + case 4: + case 9: + creg = readb(GEMINI_CPUSTAT); + if (((creg & 0xc) >> 2) != 1) + printk("Dual-604 boards don't support the use of L2\n"); + else + writeb(1, GEMINI_L2CFG); + return; + default: + printk("Unknown processor; L2 left disabled\n"); + return; + } + + cache |= ((1<<reg) << 25); + cache |= (L2CR_L2RAM_MASK|L2CR_L2CTL|L2CR_L2DO); + _set_L2CR(0); + _set_L2CR(cache | L2CR_L2E); + +} + +void +gemini_restart(char *cmd) +{ + local_irq_disable(); + /* make a clean restart, not via the MPIC */ + _gemini_reboot(); + for(;;); +} + +void +gemini_power_off(void) +{ + for(;;); +} + +void +gemini_halt(void) +{ + gemini_restart(NULL); +} + +void __init gemini_init_IRQ(void) +{ + /* gemini has no 8259 */ + openpic_init(1, 0, 0, -1); +} + +#define gemini_rtc_read(x) (readb(GEMINI_RTC+(x))) +#define gemini_rtc_write(val,x) (writeb((val),(GEMINI_RTC+(x)))) + +/* ensure that the RTC is up and running */ +long __init gemini_time_init(void) +{ + unsigned char reg; + + reg = gemini_rtc_read(M48T35_RTC_CONTROL); + + if ( reg & M48T35_RTC_STOPPED ) { + printk(KERN_INFO "M48T35 real-time-clock was stopped. Now starting...\n"); + gemini_rtc_write((reg & ~(M48T35_RTC_STOPPED)), M48T35_RTC_CONTROL); + gemini_rtc_write((reg | M48T35_RTC_SET), M48T35_RTC_CONTROL); + } + return 0; +} + +#undef DEBUG_RTC + +unsigned long +gemini_get_rtc_time(void) +{ + unsigned int year, mon, day, hour, min, sec; + unsigned char reg; + + reg = gemini_rtc_read(M48T35_RTC_CONTROL); + gemini_rtc_write((reg|M48T35_RTC_READ), M48T35_RTC_CONTROL); +#ifdef DEBUG_RTC + printk("get rtc: reg = %x\n", reg); +#endif + + do { + sec = gemini_rtc_read(M48T35_RTC_SECONDS); + min = gemini_rtc_read(M48T35_RTC_MINUTES); + hour = gemini_rtc_read(M48T35_RTC_HOURS); + day = gemini_rtc_read(M48T35_RTC_DOM); + mon = gemini_rtc_read(M48T35_RTC_MONTH); + year = gemini_rtc_read(M48T35_RTC_YEAR); + } while( sec != gemini_rtc_read(M48T35_RTC_SECONDS)); +#ifdef DEBUG_RTC + printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n", + sec, min, hour, day, mon, year); +#endif + + gemini_rtc_write(reg, M48T35_RTC_CONTROL); + + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + + if ((year += 1900) < 1970) + year += 100; +#ifdef DEBUG_RTC + printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n", + sec, min, hour, day, mon, year); +#endif + + return mktime( year, mon, day, hour, min, sec ); +} + + +int +gemini_set_rtc_time( unsigned long now ) +{ + unsigned char reg; + struct rtc_time tm; + + to_tm( now, &tm ); + + reg = gemini_rtc_read(M48T35_RTC_CONTROL); +#ifdef DEBUG_RTC + printk("set rtc: reg = %x\n", reg); +#endif + + gemini_rtc_write((reg|M48T35_RTC_SET), M48T35_RTC_CONTROL); +#ifdef DEBUG_RTC + printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n", + tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year); +#endif + + tm.tm_year -= 1900; + BIN_TO_BCD(tm.tm_sec); + BIN_TO_BCD(tm.tm_min); + BIN_TO_BCD(tm.tm_hour); + BIN_TO_BCD(tm.tm_mon); + BIN_TO_BCD(tm.tm_mday); + BIN_TO_BCD(tm.tm_year); +#ifdef DEBUG_RTC + printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n", + tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year); +#endif + + gemini_rtc_write(tm.tm_sec, M48T35_RTC_SECONDS); + gemini_rtc_write(tm.tm_min, M48T35_RTC_MINUTES); + gemini_rtc_write(tm.tm_hour, M48T35_RTC_HOURS); + gemini_rtc_write(tm.tm_mday, M48T35_RTC_DOM); + gemini_rtc_write(tm.tm_mon, M48T35_RTC_MONTH); + gemini_rtc_write(tm.tm_year, M48T35_RTC_YEAR); + + /* done writing */ + gemini_rtc_write(reg, M48T35_RTC_CONTROL); + + if ((time_state == TIME_ERROR) || (time_state == TIME_BAD)) + time_state = TIME_OK; + + return 0; +} + +/* use the RTC to determine the decrementer count */ +void __init gemini_calibrate_decr(void) +{ + int freq, divisor; + unsigned char reg; + + /* determine processor bus speed */ + reg = readb(GEMINI_BSTAT); + + switch(((reg & 0x0c)>>2)&0x3) { + case 0: + default: + freq = 66667; + break; + case 1: + freq = 83000; + break; + case 2: + freq = 100000; + break; + } + + freq *= 1000; + divisor = 4; + tb_ticks_per_jiffy = freq / HZ / divisor; + tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000); +} + +unsigned long __init gemini_find_end_of_memory(void) +{ + unsigned long total; + unsigned char reg; + + reg = readb(GEMINI_MEMCFG); + total = ((1<<((reg & 0x7) - 1)) * + (8<<((reg >> 3) & 0x7))); + total *= (1024*1024); + return total; +} + +static void __init +gemini_map_io(void) +{ + io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO); + io_block_mapping(0x80000000, 0x80000000, 0x10000000, _PAGE_IO); +} + +#ifdef CONFIG_SMP +static int +smp_gemini_probe(void) +{ + int i, nr; + + nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK) >> 2; + if (nr == 0) + nr = 4; + + if (nr > 1) { + openpic_request_IPIs(); + for (i = 1; i < nr; ++i) + smp_hw_index[i] = i; + } + + return nr; +} + +static void +smp_gemini_kick_cpu(int nr) +{ + openpic_reset_processor_phys(1 << nr); + openpic_reset_processor_phys(0); +} + +static void +smp_gemini_setup_cpu(int cpu_nr) +{ + if (OpenPIC_Addr) + do_openpic_setup_cpu(); + if (cpu_nr > 0) + gemini_init_l2(); +} + +static struct smp_ops_t gemini_smp_ops = { + smp_openpic_message_pass, + smp_gemini_probe, + smp_gemini_kick_cpu, + smp_gemini_setup_cpu, + .give_timebase = smp_generic_give_timebase, + .take_timebase = smp_generic_take_timebase, +}; +#endif /* CONFIG_SMP */ + +void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + int i; + + /* Restore BATs for now */ + mtspr(SPRN_DBAT3U, 0xf0001fff); + mtspr(SPRN_DBAT3L, 0xf000002a); + + parse_bootinfo(find_bootinfo()); + + for(i = 0; i < GEMINI_LEDS; i++) + gemini_led_off(i); + + ISA_DMA_THRESHOLD = 0; + DMA_MODE_READ = 0; + DMA_MODE_WRITE = 0; + +#ifdef CONFIG_BLK_DEV_INITRD + if ( r4 ) + { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif + + ppc_md.setup_arch = gemini_setup_arch; + ppc_md.show_cpuinfo = gemini_show_cpuinfo; + ppc_md.irq_canonicalize = NULL; + ppc_md.init_IRQ = gemini_init_IRQ; + ppc_md.get_irq = openpic_get_irq; + ppc_md.init = NULL; + + ppc_md.restart = gemini_restart; + ppc_md.power_off = gemini_power_off; + ppc_md.halt = gemini_halt; + + ppc_md.time_init = gemini_time_init; + ppc_md.set_rtc_time = gemini_set_rtc_time; + ppc_md.get_rtc_time = gemini_get_rtc_time; + ppc_md.calibrate_decr = gemini_calibrate_decr; + + ppc_md.find_end_of_memory = gemini_find_end_of_memory; + ppc_md.setup_io_mappings = gemini_map_io; + + ppc_md.pcibios_fixup_bus = gemini_pcibios_fixup; + +#ifdef CONFIG_SMP + ppc_md.smp_ops = &gemini_smp_ops; +#endif /* CONFIG_SMP */ +} diff --git a/arch/ppc/platforms/hdpu.c b/arch/ppc/platforms/hdpu.c new file mode 100644 index 00000000000..b659d7b3d74 --- /dev/null +++ b/arch/ppc/platforms/hdpu.c @@ -0,0 +1,1062 @@ + +/* + * arch/ppc/platforms/hdpu_setup.c + * + * Board setup routines for the Sky Computers HDPU Compute Blade. + * + * Written by Brian Waite <waite@skycomputers.com> + * + * Based on code done by - Mark A. Greer <mgreer@mvista.com> + * Rabeeh Khoury - rabeeh@galileo.co.il + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/config.h> + +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/ide.h> +#include <linux/seq_file.h> + +#include <linux/initrd.h> +#include <linux/root_dev.h> +#include <linux/smp.h> + +#include <asm/time.h> +#include <asm/machdep.h> +#include <asm/todc.h> +#include <asm/mv64x60.h> +#include <asm/ppcboot.h> +#include <platforms/hdpu.h> +#include <linux/mv643xx.h> +#include <linux/hdpu_features.h> +#include <linux/device.h> +#include <linux/mtd/physmap.h> + +#define BOARD_VENDOR "Sky Computers" +#define BOARD_MACHINE "HDPU-CB-A" + +bd_t ppcboot_bd; +int ppcboot_bd_valid = 0; + +static mv64x60_handle_t bh; + +extern char cmd_line[]; + +unsigned long hdpu_find_end_of_memory(void); +void hdpu_mpsc_progress(char *s, unsigned short hex); +void hdpu_heartbeat(void); + +static void parse_bootinfo(unsigned long r3, + unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7); +static void hdpu_set_l1pe(void); +static void hdpu_cpustate_set(unsigned char new_state); +#ifdef CONFIG_SMP +static spinlock_t timebase_lock = SPIN_LOCK_UNLOCKED; +static unsigned int timebase_upper = 0, timebase_lower = 0; +extern int smp_tb_synchronized; + +void __devinit hdpu_tben_give(void); +void __devinit hdpu_tben_take(void); +#endif + +static int __init +hdpu_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); + + if (hose->index == 0) { + static char pci_irq_table[][4] = { + {HDPU_PCI_0_IRQ, 0, 0, 0}, + {HDPU_PCI_0_IRQ, 0, 0, 0}, + }; + + const long min_idsel = 1, max_idsel = 2, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; + } else { + static char pci_irq_table[][4] = { + {HDPU_PCI_1_IRQ, 0, 0, 0}, + }; + + const long min_idsel = 1, max_idsel = 1, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; + } +} + +static void __init hdpu_intr_setup(void) +{ + mv64x60_write(&bh, MV64x60_GPP_IO_CNTL, + (1 | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | + (1 << 6) | (1 << 7) | (1 << 12) | (1 << 16) | + (1 << 18) | (1 << 19) | (1 << 20) | (1 << 21) | + (1 << 22) | (1 << 23) | (1 << 24) | (1 << 25) | + (1 << 26) | (1 << 27) | (1 << 28) | (1 << 29))); + + /* XXXX Erranum FEr PCI-#8 */ + mv64x60_clr_bits(&bh, MV64x60_PCI0_CMD, (1 << 5) | (1 << 9)); + mv64x60_clr_bits(&bh, MV64x60_PCI1_CMD, (1 << 5) | (1 << 9)); + + /* + * Dismiss and then enable interrupt on GPP interrupt cause + * for CPU #0 + */ + mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, ~((1 << 8) | (1 << 13))); + mv64x60_set_bits(&bh, MV64x60_GPP_INTR_MASK, (1 << 8) | (1 << 13)); + + /* + * Dismiss and then enable interrupt on CPU #0 high cause reg + * BIT25 summarizes GPP interrupts 8-15 + */ + mv64x60_set_bits(&bh, MV64360_IC_CPU0_INTR_MASK_HI, (1 << 25)); +} + +static void __init hdpu_setup_peripherals(void) +{ + unsigned int val; + + mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN, + HDPU_EMB_FLASH_BASE, HDPU_EMB_FLASH_SIZE, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN); + + mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_0_WIN, + HDPU_TBEN_BASE, HDPU_TBEN_SIZE, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_0_WIN); + + mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN, + HDPU_NEXUS_ID_BASE, HDPU_NEXUS_ID_SIZE, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_1_WIN); + + mv64x60_set_32bit_window(&bh, MV64x60_CPU2SRAM_WIN, + HDPU_INTERNAL_SRAM_BASE, + HDPU_INTERNAL_SRAM_SIZE, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN); + + bh.ci->disable_window_32bit(&bh, MV64x60_ENET2MEM_4_WIN); + mv64x60_set_32bit_window(&bh, MV64x60_ENET2MEM_4_WIN, 0, 0, 0); + + mv64x60_clr_bits(&bh, MV64x60_PCI0_PCI_DECODE_CNTL, (1 << 3)); + mv64x60_clr_bits(&bh, MV64x60_PCI1_PCI_DECODE_CNTL, (1 << 3)); + mv64x60_clr_bits(&bh, MV64x60_TIMR_CNTR_0_3_CNTL, + ((1 << 0) | (1 << 8) | (1 << 16) | (1 << 24))); + + /* Enable pipelining */ + mv64x60_set_bits(&bh, MV64x60_CPU_CONFIG, (1 << 13)); + /* Enable Snoop Pipelineing */ + mv64x60_set_bits(&bh, MV64360_D_UNIT_CONTROL_HIGH, (1 << 24)); + + /* + * Change DRAM read buffer assignment. + * Assign read buffer 0 dedicated only for CPU, + * and the rest read buffer 1. + */ + val = mv64x60_read(&bh, MV64360_SDRAM_CONFIG); + val = val & 0x03ffffff; + val = val | 0xf8000000; + mv64x60_write(&bh, MV64360_SDRAM_CONFIG, val); + + /* + * Configure internal SRAM - + * Cache coherent write back, if CONFIG_MV64360_SRAM_CACHE_COHERENT set + * Parity enabled. + * Parity error propagation + * Arbitration not parked for CPU only + * Other bits are reserved. + */ +#ifdef CONFIG_MV64360_SRAM_CACHE_COHERENT + mv64x60_write(&bh, MV64360_SRAM_CONFIG, 0x001600b2); +#else + mv64x60_write(&bh, MV64360_SRAM_CONFIG, 0x001600b0); +#endif + + hdpu_intr_setup(); +} + +static void __init hdpu_setup_bridge(void) +{ + struct mv64x60_setup_info si; + int i; + + memset(&si, 0, sizeof(si)); + + si.phys_reg_base = HDPU_BRIDGE_REG_BASE; + si.pci_0.enable_bus = 1; + si.pci_0.pci_io.cpu_base = HDPU_PCI0_IO_START_PROC_ADDR; + si.pci_0.pci_io.pci_base_hi = 0; + si.pci_0.pci_io.pci_base_lo = HDPU_PCI0_IO_START_PCI_ADDR; + si.pci_0.pci_io.size = HDPU_PCI0_IO_SIZE; + si.pci_0.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE; + si.pci_0.pci_mem[0].cpu_base = HDPU_PCI0_MEM_START_PROC_ADDR; + si.pci_0.pci_mem[0].pci_base_hi = HDPU_PCI0_MEM_START_PCI_HI_ADDR; + si.pci_0.pci_mem[0].pci_base_lo = HDPU_PCI0_MEM_START_PCI_LO_ADDR; + si.pci_0.pci_mem[0].size = HDPU_PCI0_MEM_SIZE; + si.pci_0.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE; + si.pci_0.pci_cmd_bits = 0; + si.pci_0.latency_timer = 0x80; + + si.pci_1.enable_bus = 1; + si.pci_1.pci_io.cpu_base = HDPU_PCI1_IO_START_PROC_ADDR; + si.pci_1.pci_io.pci_base_hi = 0; + si.pci_1.pci_io.pci_base_lo = HDPU_PCI1_IO_START_PCI_ADDR; + si.pci_1.pci_io.size = HDPU_PCI1_IO_SIZE; + si.pci_1.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE; + si.pci_1.pci_mem[0].cpu_base = HDPU_PCI1_MEM_START_PROC_ADDR; + si.pci_1.pci_mem[0].pci_base_hi = HDPU_PCI1_MEM_START_PCI_HI_ADDR; + si.pci_1.pci_mem[0].pci_base_lo = HDPU_PCI1_MEM_START_PCI_LO_ADDR; + si.pci_1.pci_mem[0].size = HDPU_PCI1_MEM_SIZE; + si.pci_1.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE; + si.pci_1.pci_cmd_bits = 0; + si.pci_1.latency_timer = 0x80; + + for (i = 0; i < MV64x60_CPU2MEM_WINDOWS; i++) { +#if defined(CONFIG_NOT_COHERENT_CACHE) + si.cpu_prot_options[i] = 0; + si.enet_options[i] = MV64360_ENET2MEM_SNOOP_NONE; + si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_NONE; + si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE; + + si.pci_1.acc_cntl_options[i] = + MV64360_PCI_ACC_CNTL_SNOOP_NONE | + MV64360_PCI_ACC_CNTL_SWAP_NONE | + MV64360_PCI_ACC_CNTL_MBURST_128_BYTES | + MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES; + + si.pci_0.acc_cntl_options[i] = + MV64360_PCI_ACC_CNTL_SNOOP_NONE | + MV64360_PCI_ACC_CNTL_SWAP_NONE | + MV64360_PCI_ACC_CNTL_MBURST_128_BYTES | + MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES; + +#else + si.cpu_prot_options[i] = 0; + si.enet_options[i] = MV64360_ENET2MEM_SNOOP_WB; /* errata */ + si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_WB; /* errata */ + si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_WB; /* errata */ + + si.pci_0.acc_cntl_options[i] = + MV64360_PCI_ACC_CNTL_SNOOP_WB | + MV64360_PCI_ACC_CNTL_SWAP_NONE | + MV64360_PCI_ACC_CNTL_MBURST_32_BYTES | + MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES; + + si.pci_1.acc_cntl_options[i] = + MV64360_PCI_ACC_CNTL_SNOOP_WB | + MV64360_PCI_ACC_CNTL_SWAP_NONE | + MV64360_PCI_ACC_CNTL_MBURST_32_BYTES | + MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES; +#endif + } + + hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR | CPUSTATE_KERNEL_INIT_PCI); + + /* Lookup PCI host bridges */ + mv64x60_init(&bh, &si); + pci_dram_offset = 0; /* System mem at same addr on PCI & cpu bus */ + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = hdpu_map_irq; + + mv64x60_set_bus(&bh, 0, 0); + bh.hose_a->first_busno = 0; + bh.hose_a->last_busno = 0xff; + bh.hose_a->last_busno = pciauto_bus_scan(bh.hose_a, 0); + + bh.hose_b->first_busno = bh.hose_a->last_busno + 1; + mv64x60_set_bus(&bh, 1, bh.hose_b->first_busno); + bh.hose_b->last_busno = 0xff; + bh.hose_b->last_busno = pciauto_bus_scan(bh.hose_b, + bh.hose_b->first_busno); + + ppc_md.pci_exclude_device = mv64x60_pci_exclude_device; + + hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR | CPUSTATE_KERNEL_INIT_REG); + /* + * Enabling of PCI internal-vs-external arbitration + * is a platform- and errata-dependent decision. + */ + return; +} + +#if defined(CONFIG_SERIAL_MPSC_CONSOLE) +static void __init hdpu_early_serial_map(void) +{ +#ifdef CONFIG_KGDB + static char first_time = 1; + +#if defined(CONFIG_KGDB_TTYS0) +#define KGDB_PORT 0 +#elif defined(CONFIG_KGDB_TTYS1) +#define KGDB_PORT 1 +#else +#error "Invalid kgdb_tty port" +#endif + + if (first_time) { + gt_early_mpsc_init(KGDB_PORT, + B9600 | CS8 | CREAD | HUPCL | CLOCAL); + first_time = 0; + } + + return; +#endif +} +#endif + +static void hdpu_init2(void) +{ + return; +} + +#if defined(CONFIG_MV643XX_ETH) +static void __init hdpu_fixup_eth_pdata(struct platform_device *pd) +{ + + struct mv643xx_eth_platform_data *eth_pd; + eth_pd = pd->dev.platform_data; + + eth_pd->port_serial_control = + mv64x60_read(&bh, MV643XX_ETH_PORT_SERIAL_CONTROL_REG(pd->id) & ~1); + + eth_pd->force_phy_addr = 1; + eth_pd->phy_addr = pd->id; + eth_pd->tx_queue_size = 400; + eth_pd->rx_queue_size = 800; +} +#endif + +static void __init hdpu_fixup_mpsc_pdata(struct platform_device *pd) +{ + + struct mpsc_pdata *pdata; + + pdata = (struct mpsc_pdata *)pd->dev.platform_data; + + pdata->max_idle = 40; + if (ppcboot_bd_valid) + pdata->default_baud = ppcboot_bd.bi_baudrate; + else + pdata->default_baud = HDPU_DEFAULT_BAUD; + pdata->brg_clk_src = HDPU_MPSC_CLK_SRC; + pdata->brg_clk_freq = HDPU_MPSC_CLK_FREQ; +} + +#if defined(CONFIG_HDPU_FEATURES) +static void __init hdpu_fixup_cpustate_pdata(struct platform_device *pd) +{ + struct platform_device *pds[1]; + pds[0] = pd; + mv64x60_pd_fixup(&bh, pds, 1); +} +#endif + +static int __init hdpu_platform_notify(struct device *dev) +{ + static struct { + char *bus_id; + void ((*rtn) (struct platform_device * pdev)); + } dev_map[] = { + { + MPSC_CTLR_NAME ".0", hdpu_fixup_mpsc_pdata}, +#if defined(CONFIG_MV643XX_ETH) + { + MV643XX_ETH_NAME ".0", hdpu_fixup_eth_pdata}, +#endif +#if defined(CONFIG_HDPU_FEATURES) + { + HDPU_CPUSTATE_NAME ".0", hdpu_fixup_cpustate_pdata}, +#endif + }; + struct platform_device *pdev; + int i; + + if (dev && dev->bus_id) + for (i = 0; i < ARRAY_SIZE(dev_map); i++) + if (!strncmp(dev->bus_id, dev_map[i].bus_id, + BUS_ID_SIZE)) { + + pdev = container_of(dev, + struct platform_device, + dev); + dev_map[i].rtn(pdev); + } + + return 0; +} + +static void __init hdpu_setup_arch(void) +{ + if (ppc_md.progress) + ppc_md.progress("hdpu_setup_arch: enter", 0); +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_SDA2; +#endif + + ppc_md.heartbeat = hdpu_heartbeat; + + ppc_md.heartbeat_reset = HZ; + ppc_md.heartbeat_count = 1; + + if (ppc_md.progress) + ppc_md.progress("hdpu_setup_arch: Enabling L2 cache", 0); + + /* Enable L1 Parity Bits */ + hdpu_set_l1pe(); + + /* Enable L2 and L3 caches (if 745x) */ + _set_L2CR(0x80080000); + + if (ppc_md.progress) + ppc_md.progress("hdpu_setup_arch: enter", 0); + + hdpu_setup_bridge(); + + hdpu_setup_peripherals(); + +#ifdef CONFIG_SERIAL_MPSC_CONSOLE + hdpu_early_serial_map(); +#endif + + printk("SKY HDPU Compute Blade \n"); + + if (ppc_md.progress) + ppc_md.progress("hdpu_setup_arch: exit", 0); + + hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR | CPUSTATE_KERNEL_OK); + return; +} +static void __init hdpu_init_irq(void) +{ + mv64360_init_irq(); +} + +static void __init hdpu_set_l1pe() +{ + unsigned long ictrl; + asm volatile ("mfspr %0, 1011":"=r" (ictrl):); + ictrl |= ICTRL_EICE | ICTRL_EDC | ICTRL_EICP; + asm volatile ("mtspr 1011, %0"::"r" (ictrl)); +} + +/* + * Set BAT 1 to map 0xf1000000 to end of physical memory space. + */ +static __inline__ void hdpu_set_bat(void) +{ + mb(); + mtspr(SPRN_DBAT1U, 0xf10001fe); + mtspr(SPRN_DBAT1L, 0xf100002a); + mb(); + + return; +} + +unsigned long __init hdpu_find_end_of_memory(void) +{ + return mv64x60_get_mem_size(CONFIG_MV64X60_NEW_BASE, + MV64x60_TYPE_MV64360); +} + +static void hdpu_reset_board(void) +{ + volatile int infinite = 1; + + hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR | CPUSTATE_KERNEL_RESET); + + local_irq_disable(); + + /* Clear all the LEDs */ + mv64x60_write(&bh, MV64x60_GPP_VALUE_CLR, ((1 << 4) | + (1 << 5) | (1 << 6))); + + /* disable and invalidate the L2 cache */ + _set_L2CR(0); + _set_L2CR(0x200000); + + /* flush and disable L1 I/D cache */ + __asm__ __volatile__ + ("\n" + "mfspr 3,1008\n" + "ori 5,5,0xcc00\n" + "ori 4,3,0xc00\n" + "andc 5,3,5\n" + "sync\n" + "mtspr 1008,4\n" + "isync\n" "sync\n" "mtspr 1008,5\n" "isync\n" "sync\n"); + + /* Hit the reset bit */ + mv64x60_write(&bh, MV64x60_GPP_VALUE_CLR, (1 << 3)); + + while (infinite) + infinite = infinite; + + return; +} + +static void hdpu_restart(char *cmd) +{ + volatile ulong i = 10000000; + + hdpu_reset_board(); + + while (i-- > 0) ; + panic("restart failed\n"); +} + +static void hdpu_halt(void) +{ + local_irq_disable(); + + hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR | CPUSTATE_KERNEL_HALT); + + /* Clear all the LEDs */ + mv64x60_write(&bh, MV64x60_GPP_VALUE_CLR, ((1 << 4) | (1 << 5) | + (1 << 6))); + while (1) ; + /* NOTREACHED */ +} + +static void hdpu_power_off(void) +{ + hdpu_halt(); + /* NOTREACHED */ +} + +static int hdpu_show_cpuinfo(struct seq_file *m) +{ + uint pvid; + + pvid = mfspr(SPRN_PVR); + seq_printf(m, "vendor\t\t: Sky Computers\n"); + seq_printf(m, "machine\t\t: HDPU Compute Blade\n"); + seq_printf(m, "PVID\t\t: 0x%x, vendor: %s\n", + pvid, (pvid & (1 << 15) ? "IBM" : "Motorola")); + + return 0; +} + +static void __init hdpu_calibrate_decr(void) +{ + ulong freq; + + if (ppcboot_bd_valid) + freq = ppcboot_bd.bi_busfreq / 4; + else + freq = 133000000; + + printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", + freq / 1000000, freq % 1000000); + + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); + + return; +} + +static void parse_bootinfo(unsigned long r3, + unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + bd_t *bd = NULL; + char *cmdline_start = NULL; + int cmdline_len = 0; + + if (r3) { + if ((r3 & 0xf0000000) == 0) + r3 += KERNELBASE; + if ((r3 & 0xf0000000) == KERNELBASE) { + bd = (void *)r3; + + memcpy(&ppcboot_bd, bd, sizeof(ppcboot_bd)); + ppcboot_bd_valid = 1; + } + } +#ifdef CONFIG_BLK_DEV_INITRD + if (r4 && r5 && r5 > r4) { + if ((r4 & 0xf0000000) == 0) + r4 += KERNELBASE; + if ((r5 & 0xf0000000) == 0) + r5 += KERNELBASE; + if ((r4 & 0xf0000000) == KERNELBASE) { + initrd_start = r4; + initrd_end = r5; + initrd_below_start_ok = 1; + } + } +#endif /* CONFIG_BLK_DEV_INITRD */ + + if (r6 && r7 && r7 > r6) { + if ((r6 & 0xf0000000) == 0) + r6 += KERNELBASE; + if ((r7 & 0xf0000000) == 0) + r7 += KERNELBASE; + if ((r6 & 0xf0000000) == KERNELBASE) { + cmdline_start = (void *)r6; + cmdline_len = (r7 - r6); + strncpy(cmd_line, cmdline_start, cmdline_len); + } + } +} + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +static int hdpu_ide_check_region(ide_ioreg_t from, unsigned int extent) +{ + return check_region(from, extent); +} + +static void +hdpu_ide_request_region(ide_ioreg_t from, unsigned int extent, const char *name) +{ + request_region(from, extent, name); + return; +} + +static void hdpu_ide_release_region(ide_ioreg_t from, unsigned int extent) +{ + release_region(from, extent); + return; +} + +static void __init +hdpu_ide_pci_init_hwif_ports(hw_regs_t * hw, ide_ioreg_t data_port, + ide_ioreg_t ctrl_port, int *irq) +{ + struct pci_dev *dev; + + pci_for_each_dev(dev) { + if (((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) || + ((dev->class >> 8) == PCI_CLASS_STORAGE_RAID)) { + hw->irq = dev->irq; + + if (irq != NULL) { + *irq = dev->irq; + } + } + } + + return; +} +#endif + +void hdpu_heartbeat(void) +{ + if (mv64x60_read(&bh, MV64x60_GPP_VALUE) & (1 << 5)) + mv64x60_write(&bh, MV64x60_GPP_VALUE_CLR, (1 << 5)); + else + mv64x60_write(&bh, MV64x60_GPP_VALUE_SET, (1 << 5)); + + ppc_md.heartbeat_count = ppc_md.heartbeat_reset; + +} + +static void __init hdpu_map_io(void) +{ + io_block_mapping(0xf1000000, 0xf1000000, 0x20000, _PAGE_IO); +} + +#ifdef CONFIG_SMP +char hdpu_smp0[] = "SMP Cpu #0"; +char hdpu_smp1[] = "SMP Cpu #1"; + +static irqreturn_t hdpu_smp_cpu0_int_handler(int irq, void *dev_id, + struct pt_regs *regs) +{ + volatile unsigned int doorbell; + + doorbell = mv64x60_read(&bh, MV64360_CPU0_DOORBELL); + + /* Ack the doorbell interrupts */ + mv64x60_write(&bh, MV64360_CPU0_DOORBELL_CLR, doorbell); + + if (doorbell & 1) { + smp_message_recv(0, regs); + } + if (doorbell & 2) { + smp_message_recv(1, regs); + } + if (doorbell & 4) { + smp_message_recv(2, regs); + } + if (doorbell & 8) { + smp_message_recv(3, regs); + } + return IRQ_HANDLED; +} + +static irqreturn_t hdpu_smp_cpu1_int_handler(int irq, void *dev_id, + struct pt_regs *regs) +{ + volatile unsigned int doorbell; + + doorbell = mv64x60_read(&bh, MV64360_CPU1_DOORBELL); + + /* Ack the doorbell interrupts */ + mv64x60_write(&bh, MV64360_CPU1_DOORBELL_CLR, doorbell); + + if (doorbell & 1) { + smp_message_recv(0, regs); + } + if (doorbell & 2) { + smp_message_recv(1, regs); + } + if (doorbell & 4) { + smp_message_recv(2, regs); + } + if (doorbell & 8) { + smp_message_recv(3, regs); + } + return IRQ_HANDLED; +} + +static void smp_hdpu_CPU_two(void) +{ + __asm__ __volatile__ + ("\n" + "lis 3,0x0000\n" + "ori 3,3,0x00c0\n" + "mtspr 26, 3\n" "li 4,0\n" "mtspr 27,4\n" "rfi"); + +} + +static int smp_hdpu_probe(void) +{ + int *cpu_count_reg; + int num_cpus = 0; + + cpu_count_reg = ioremap(HDPU_NEXUS_ID_BASE, HDPU_NEXUS_ID_SIZE); + if (cpu_count_reg) { + num_cpus = (*cpu_count_reg >> 20) & 0x3; + iounmap(cpu_count_reg); + } + + /* Validate the bits in the CPLD. If we could not map the reg, return 2. + * If the register reported 0 or 3, return 2. + * Older CPLD revisions set these bits to all ones (val = 3). + */ + if ((num_cpus < 1) || (num_cpus > 2)) { + printk + ("Unable to determine the number of processors %d . deafulting to 2.\n", + num_cpus); + num_cpus = 2; + } + return num_cpus; +} + +static void +smp_hdpu_message_pass(int target, int msg, unsigned long data, int wait) +{ + if (msg > 0x3) { + printk("SMP %d: smp_message_pass: unknown msg %d\n", + smp_processor_id(), msg); + return; + } + switch (target) { + case MSG_ALL: + mv64x60_write(&bh, MV64360_CPU0_DOORBELL, 1 << msg); + mv64x60_write(&bh, MV64360_CPU1_DOORBELL, 1 << msg); + break; + case MSG_ALL_BUT_SELF: + if (smp_processor_id()) + mv64x60_write(&bh, MV64360_CPU0_DOORBELL, 1 << msg); + else + mv64x60_write(&bh, MV64360_CPU1_DOORBELL, 1 << msg); + break; + default: + if (target == 0) + mv64x60_write(&bh, MV64360_CPU0_DOORBELL, 1 << msg); + else + mv64x60_write(&bh, MV64360_CPU1_DOORBELL, 1 << msg); + break; + } +} + +static void smp_hdpu_kick_cpu(int nr) +{ + volatile unsigned int *bootaddr; + + if (ppc_md.progress) + ppc_md.progress("smp_hdpu_kick_cpu", 0); + + hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR | CPUSTATE_KERNEL_CPU1_KICK); + + /* Disable BootCS. Must also reduce the windows size to zero. */ + bh.ci->disable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN); + mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN, 0, 0, 0); + + bootaddr = ioremap(HDPU_INTERNAL_SRAM_BASE, HDPU_INTERNAL_SRAM_SIZE); + if (!bootaddr) { + if (ppc_md.progress) + ppc_md.progress("smp_hdpu_kick_cpu: ioremap failed", 0); + return; + } + + memcpy((void *)(bootaddr + 0x40), (void *)&smp_hdpu_CPU_two, 0x20); + + /* map SRAM to 0xfff00000 */ + bh.ci->disable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN); + + mv64x60_set_32bit_window(&bh, MV64x60_CPU2SRAM_WIN, + 0xfff00000, HDPU_INTERNAL_SRAM_SIZE, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN); + + /* Enable CPU1 arbitration */ + mv64x60_clr_bits(&bh, MV64x60_CPU_MASTER_CNTL, (1 << 9)); + + /* + * Wait 100mSecond until other CPU has reached __secondary_start. + * When it reaches, it is permittable to rever the SRAM mapping etc... + */ + mdelay(100); + *(unsigned long *)KERNELBASE = nr; + asm volatile ("dcbf 0,%0"::"r" (KERNELBASE):"memory"); + + iounmap(bootaddr); + + /* Set up window for internal sram (256KByte insize) */ + bh.ci->disable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN); + mv64x60_set_32bit_window(&bh, MV64x60_CPU2SRAM_WIN, + HDPU_INTERNAL_SRAM_BASE, + HDPU_INTERNAL_SRAM_SIZE, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN); + /* + * Set up windows for embedded FLASH (using boot CS window). + */ + + bh.ci->disable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN); + mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN, + HDPU_EMB_FLASH_BASE, HDPU_EMB_FLASH_SIZE, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN); +} + +static void smp_hdpu_setup_cpu(int cpu_nr) +{ + if (cpu_nr == 0) { + if (ppc_md.progress) + ppc_md.progress("smp_hdpu_setup_cpu 0", 0); + mv64x60_write(&bh, MV64360_CPU0_DOORBELL_CLR, 0xff); + mv64x60_write(&bh, MV64360_CPU0_DOORBELL_MASK, 0xff); + request_irq(60, hdpu_smp_cpu0_int_handler, + SA_INTERRUPT, hdpu_smp0, 0); + } + + if (cpu_nr == 1) { + if (ppc_md.progress) + ppc_md.progress("smp_hdpu_setup_cpu 1", 0); + + hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR | + CPUSTATE_KERNEL_CPU1_OK); + + /* Enable L1 Parity Bits */ + hdpu_set_l1pe(); + + /* Enable L2 cache */ + _set_L2CR(0); + _set_L2CR(0x80080000); + + mv64x60_write(&bh, MV64360_CPU1_DOORBELL_CLR, 0x0); + mv64x60_write(&bh, MV64360_CPU1_DOORBELL_MASK, 0xff); + request_irq(28, hdpu_smp_cpu1_int_handler, + SA_INTERRUPT, hdpu_smp1, 0); + } + +} + +void __devinit hdpu_tben_give() +{ + volatile unsigned long *val = 0; + + /* By writing 0 to the TBEN_BASE, the timebases is frozen */ + val = ioremap(HDPU_TBEN_BASE, 4); + *val = 0; + mb(); + + spin_lock(&timebase_lock); + timebase_upper = get_tbu(); + timebase_lower = get_tbl(); + spin_unlock(&timebase_lock); + + while (timebase_upper || timebase_lower) + barrier(); + + /* By writing 1 to the TBEN_BASE, the timebases is thawed */ + *val = 1; + mb(); + + iounmap(val); + +} + +void __devinit hdpu_tben_take() +{ + while (!(timebase_upper || timebase_lower)) + barrier(); + + spin_lock(&timebase_lock); + set_tb(timebase_upper, timebase_lower); + timebase_upper = 0; + timebase_lower = 0; + spin_unlock(&timebase_lock); +} + +static struct smp_ops_t hdpu_smp_ops = { + .message_pass = smp_hdpu_message_pass, + .probe = smp_hdpu_probe, + .kick_cpu = smp_hdpu_kick_cpu, + .setup_cpu = smp_hdpu_setup_cpu, + .give_timebase = hdpu_tben_give, + .take_timebase = hdpu_tben_take, +}; +#endif /* CONFIG_SMP */ + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + parse_bootinfo(r3, r4, r5, r6, r7); + + isa_mem_base = 0; + + ppc_md.setup_arch = hdpu_setup_arch; + ppc_md.init = hdpu_init2; + ppc_md.show_cpuinfo = hdpu_show_cpuinfo; + ppc_md.init_IRQ = hdpu_init_irq; + ppc_md.get_irq = mv64360_get_irq; + ppc_md.restart = hdpu_restart; + ppc_md.power_off = hdpu_power_off; + ppc_md.halt = hdpu_halt; + ppc_md.find_end_of_memory = hdpu_find_end_of_memory; + ppc_md.calibrate_decr = hdpu_calibrate_decr; + ppc_md.setup_io_mappings = hdpu_map_io; + + bh.p_base = CONFIG_MV64X60_NEW_BASE; + bh.v_base = (unsigned long *)bh.p_base; + + hdpu_set_bat(); + +#if defined(CONFIG_SERIAL_TEXT_DEBUG) + ppc_md.progress = hdpu_mpsc_progress; /* embedded UART */ + mv64x60_progress_init(bh.p_base); +#endif /* CONFIG_SERIAL_TEXT_DEBUG */ + +#ifdef CONFIG_SMP + ppc_md.smp_ops = &hdpu_smp_ops; +#endif /* CONFIG_SMP */ + +#if defined(CONFIG_SERIAL_MPSC) || defined(CONFIG_MV643XX_ETH) + platform_notify = hdpu_platform_notify; +#endif + return; +} + +#if defined(CONFIG_SERIAL_TEXT_DEBUG) && defined(CONFIG_SERIAL_MPSC_CONSOLE) +/* SMP safe version of the serial text debug routine. Uses Semaphore 0 */ +void hdpu_mpsc_progress(char *s, unsigned short hex) +{ + while (mv64x60_read(&bh, MV64360_WHO_AM_I) != + mv64x60_read(&bh, MV64360_SEMAPHORE_0)) { + } + mv64x60_mpsc_progress(s, hex); + mv64x60_write(&bh, MV64360_SEMAPHORE_0, 0xff); +} +#endif + +static void hdpu_cpustate_set(unsigned char new_state) +{ + unsigned int state = (new_state << 21); + mv64x60_write(&bh, MV64x60_GPP_VALUE_CLR, (0xff << 21)); + mv64x60_write(&bh, MV64x60_GPP_VALUE_CLR, state); +} + +#ifdef CONFIG_MTD_PHYSMAP +static struct mtd_partition hdpu_partitions[] = { + { + .name = "Root FS", + .size = 0x03400000, + .offset = 0, + .mask_flags = 0, + },{ + .name = "User FS", + .size = 0x00800000, + .offset = 0x03400000, + .mask_flags = 0, + },{ + .name = "Kernel Image", + .size = 0x002C0000, + .offset = 0x03C00000, + .mask_flags = 0, + },{ + .name = "bootEnv", + .size = 0x00040000, + .offset = 0x03EC0000, + .mask_flags = 0, + },{ + .name = "bootROM", + .size = 0x00100000, + .offset = 0x03F00000, + .mask_flags = 0, + } +}; + +static int __init hdpu_setup_mtd(void) +{ + + physmap_set_partitions(hdpu_partitions, 5); + return 0; +} + +arch_initcall(hdpu_setup_mtd); +#endif + +#ifdef CONFIG_HDPU_FEATURES + +static struct resource hdpu_cpustate_resources[] = { + [0] = { + .name = "addr base", + .start = MV64x60_GPP_VALUE_SET, + .end = MV64x60_GPP_VALUE_CLR + 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct resource hdpu_nexus_resources[] = { + [0] = { + .name = "nexus register", + .start = HDPU_NEXUS_ID_BASE, + .end = HDPU_NEXUS_ID_BASE + HDPU_NEXUS_ID_SIZE, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device hdpu_cpustate_device = { + .name = HDPU_CPUSTATE_NAME, + .id = 0, + .num_resources = ARRAY_SIZE(hdpu_cpustate_resources), + .resource = hdpu_cpustate_resources, +}; + +static struct platform_device hdpu_nexus_device = { + .name = HDPU_NEXUS_NAME, + .id = 0, + .num_resources = ARRAY_SIZE(hdpu_nexus_resources), + .resource = hdpu_nexus_resources, +}; + +static int __init hdpu_add_pds(void) +{ + platform_device_register(&hdpu_cpustate_device); + platform_device_register(&hdpu_nexus_device); + return 0; +} + +arch_initcall(hdpu_add_pds); +#endif diff --git a/arch/ppc/platforms/hdpu.h b/arch/ppc/platforms/hdpu.h new file mode 100644 index 00000000000..07c3cffb5c7 --- /dev/null +++ b/arch/ppc/platforms/hdpu.h @@ -0,0 +1,82 @@ +/* + * arch/ppc/platforms/hdpu.h + * + * Definitions for Sky Computers HDPU board. + * + * Brian Waite <waite@skycomputers.com> + * + * Based on code done by Rabeeh Khoury - rabeeh@galileo.co.il + * Based on code done by Mark A. Greer <mgreer@mvista.com> + * Based on code done by Tim Montgomery <timm@artesyncp.com> + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/* + * The MV64360 has 2 PCI buses each with 1 window from the CPU bus to + * PCI I/O space and 4 windows from the CPU bus to PCI MEM space. + * We'll only use one PCI MEM window on each PCI bus. + * + * This is the CPU physical memory map (windows must be at least 64K and start + * on a boundary that is a multiple of the window size): + * + * 0x80000000-0x8fffffff - PCI 0 MEM + * 0xa0000000-0xafffffff - PCI 1 MEM + * 0xc0000000-0xc0ffffff - PCI 0 I/O + * 0xc1000000-0xc1ffffff - PCI 1 I/O + + * 0xf1000000-0xf100ffff - MV64360 Registers + * 0xf1010000-0xfb9fffff - HOLE + * 0xfbfa0000-0xfbfaffff - TBEN + * 0xfbf00000-0xfbfbffff - NEXUS + * 0xfbfc0000-0xfbffffff - Internal SRAM + * 0xfc000000-0xffffffff - Boot window + */ + +#ifndef __PPC_PLATFORMS_HDPU_H +#define __PPC_PLATFORMS_HDPU_H + +/* CPU Physical Memory Map setup. */ +#define HDPU_BRIDGE_REG_BASE 0xf1000000 + +#define HDPU_TBEN_BASE 0xfbfa0000 +#define HDPU_TBEN_SIZE 0x00010000 +#define HDPU_NEXUS_ID_BASE 0xfbfb0000 +#define HDPU_NEXUS_ID_SIZE 0x00010000 +#define HDPU_INTERNAL_SRAM_BASE 0xfbfc0000 +#define HDPU_INTERNAL_SRAM_SIZE 0x00040000 +#define HDPU_EMB_FLASH_BASE 0xfc000000 +#define HDPU_EMB_FLASH_SIZE 0x04000000 + +/* PCI Mappings */ + +#define HDPU_PCI0_MEM_START_PROC_ADDR 0x80000000 +#define HDPU_PCI0_MEM_START_PCI_HI_ADDR 0x00000000 +#define HDPU_PCI0_MEM_START_PCI_LO_ADDR HDPU_PCI0_MEM_START_PROC_ADDR +#define HDPU_PCI0_MEM_SIZE 0x10000000 + +#define HDPU_PCI1_MEM_START_PROC_ADDR 0xc0000000 +#define HDPU_PCI1_MEM_START_PCI_HI_ADDR 0x00000000 +#define HDPU_PCI1_MEM_START_PCI_LO_ADDR HDPU_PCI1_MEM_START_PROC_ADDR +#define HDPU_PCI1_MEM_SIZE 0x20000000 + +#define HDPU_PCI0_IO_START_PROC_ADDR 0xc0000000 +#define HDPU_PCI0_IO_START_PCI_ADDR 0x00000000 +#define HDPU_PCI0_IO_SIZE 0x01000000 + +#define HDPU_PCI1_IO_START_PROC_ADDR 0xc1000000 +#define HDPU_PCI1_IO_START_PCI_ADDR 0x01000000 +#define HDPU_PCI1_IO_SIZE 0x01000000 + +#define HDPU_DEFAULT_BAUD 115200 +#define HDPU_MPSC_CLK_SRC 8 /* TCLK */ +#define HDPU_MPSC_CLK_FREQ 133000000 /* 133 Mhz */ + +#define HDPU_PCI_0_IRQ (8+64) +#define HDPU_PCI_1_IRQ (13+64) + +#endif /* __PPC_PLATFORMS_HDPU_H */ diff --git a/arch/ppc/platforms/hermes.h b/arch/ppc/platforms/hermes.h new file mode 100644 index 00000000000..198fc590b9f --- /dev/null +++ b/arch/ppc/platforms/hermes.h @@ -0,0 +1,27 @@ +/* + * Multidata HERMES-PRO ( / SL ) board specific definitions + * + * Copyright (c) 2000, 2001 Wolfgang Denk (wd@denx.de) + */ + +#ifndef __MACH_HERMES_H +#define __MACH_HERMES_H + +#include <linux/config.h> + +#include <asm/ppcboot.h> + +#define HERMES_IMMR_BASE 0xFF000000 /* phys. addr of IMMR */ +#define HERMES_IMAP_SIZE (64 * 1024) /* size of mapped area */ + +#define IMAP_ADDR HERMES_IMMR_BASE /* physical base address of IMMR area */ +#define IMAP_SIZE HERMES_IMAP_SIZE /* mapped size of IMMR area */ + +#define FEC_INTERRUPT 9 /* = SIU_LEVEL4 */ +#define CPM_INTERRUPT 11 /* = SIU_LEVEL5 (was: SIU_LEVEL2) */ + +/* We don't use the 8259. +*/ +#define NR_8259_INTS 0 + +#endif /* __MACH_HERMES_H */ diff --git a/arch/ppc/platforms/ip860.h b/arch/ppc/platforms/ip860.h new file mode 100644 index 00000000000..8c3836c5f05 --- /dev/null +++ b/arch/ppc/platforms/ip860.h @@ -0,0 +1,36 @@ +/* + * MicroSys IP860 VMEBus board specific definitions + * + * Copyright (c) 2000, 2001 Wolfgang Denk (wd@denx.de) + */ + +#ifndef __MACH_IP860_H +#define __MACH_IP860_H + +#include <linux/config.h> + +#include <asm/ppcboot.h> + +#define IP860_IMMR_BASE 0xF1000000 /* phys. addr of IMMR */ +#define IP860_IMAP_SIZE (64 * 1024) /* size of mapped area */ + +#define IMAP_ADDR IP860_IMMR_BASE /* physical base address of IMMR area */ +#define IMAP_SIZE IP860_IMAP_SIZE /* mapped size of IMMR area */ + +/* + * MPC8xx Chip Select Usage + */ +#define IP860_BOOT_CS 0 /* Boot (VMEBus or Flash) Chip Select 0 */ +#define IP860_FLASH_CS 1 /* Flash is on Chip Select 1 */ +#define IP860_SDRAM_CS 2 /* SDRAM is on Chip Select 2 */ +#define IP860_SRAM_CS 3 /* SRAM is on Chip Select 3 */ +#define IP860_BCSR_CS 4 /* BCSR is on Chip Select 4 */ +#define IP860_IP_CS 5 /* IP Slots are on Chip Select 5 */ +#define IP860_VME_STD_CS 6 /* VME Standard I/O is on Chip Select 6 */ +#define IP860_VME_SHORT_CS 7 /* VME Short I/O is on Chip Select 7 */ + +/* We don't use the 8259. +*/ +#define NR_8259_INTS 0 + +#endif /* __MACH_IP860_H */ diff --git a/arch/ppc/platforms/ivms8.h b/arch/ppc/platforms/ivms8.h new file mode 100644 index 00000000000..d4be310f808 --- /dev/null +++ b/arch/ppc/platforms/ivms8.h @@ -0,0 +1,56 @@ +/* + * Speech Design Integrated Voicemail board specific definitions + * - IVMS8 (small, 8 channels) + * - IVML24 (large, 24 channels) + * + * In 2.5 when we force a new bootloader, we can merge these two, and add + * in _MACH_'s for them. -- Tom + * + * Copyright (c) 2000, 2001 Wolfgang Denk (wd@denx.de) + */ + +#ifdef __KERNEL__ +#ifndef __ASM_IVMS8_H__ +#define __ASM_IVMS8_H__ + +#include <linux/config.h> + +#include <asm/ppcboot.h> + +#define IVMS_IMMR_BASE 0xFFF00000 /* phys. addr of IMMR */ +#define IVMS_IMAP_SIZE (64 * 1024) /* size of mapped area */ + +#define IMAP_ADDR IVMS_IMMR_BASE /* phys. base address of IMMR area */ +#define IMAP_SIZE IVMS_IMAP_SIZE /* mapped size of IMMR area */ + +#define PCMCIA_MEM_ADDR ((uint)0xFE100000) +#define PCMCIA_MEM_SIZE ((uint)(64 * 1024)) + +#define FEC_INTERRUPT 9 /* = SIU_LEVEL4 */ +#define IDE0_INTERRUPT 10 /* = IRQ5 */ +#define CPM_INTERRUPT 11 /* = SIU_LEVEL5 (was: SIU_LEVEL2) */ +#define PHY_INTERRUPT 12 /* = IRQ6 */ + +/* override the default number of IDE hardware interfaces */ +#define MAX_HWIFS 1 + +/* + * Definitions for IDE0 Interface + */ +#define IDE0_BASE_OFFSET 0x0000 /* Offset in PCMCIA memory */ +#define IDE0_DATA_REG_OFFSET 0x0000 +#define IDE0_ERROR_REG_OFFSET 0x0081 +#define IDE0_NSECTOR_REG_OFFSET 0x0082 +#define IDE0_SECTOR_REG_OFFSET 0x0083 +#define IDE0_LCYL_REG_OFFSET 0x0084 +#define IDE0_HCYL_REG_OFFSET 0x0085 +#define IDE0_SELECT_REG_OFFSET 0x0086 +#define IDE0_STATUS_REG_OFFSET 0x0087 +#define IDE0_CONTROL_REG_OFFSET 0x0106 +#define IDE0_IRQ_REG_OFFSET 0x000A /* not used */ + +/* We don't use the 8259. */ +#define NR_8259_INTS 0 + +#endif /* __ASM_IVMS8_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/k2.c b/arch/ppc/platforms/k2.c new file mode 100644 index 00000000000..aacb438708f --- /dev/null +++ b/arch/ppc/platforms/k2.c @@ -0,0 +1,613 @@ +/* + * arch/ppc/platforms/k2.c + * + * Board setup routines for SBS K2 + * + * Author: Matt Porter <mporter@mvista.com> + * + * Updated by: Randy Vinson <rvinson@mvista.com. + * + * 2001-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. + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/types.h> +#include <linux/major.h> +#include <linux/initrd.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/ide.h> +#include <linux/irq.h> +#include <linux/seq_file.h> +#include <linux/root_dev.h> + +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/machdep.h> +#include <asm/time.h> +#include <asm/i8259.h> +#include <asm/todc.h> +#include <asm/bootinfo.h> + +#include <syslib/cpc710.h> +#include "k2.h" + +extern unsigned long loops_per_jiffy; +extern void gen550_progress(char *, unsigned short); + +static unsigned int cpu_7xx[16] = { + 0, 15, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0 +}; +static unsigned int cpu_6xx[16] = { + 0, 0, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 0, 12, 7, 0 +}; + +static inline int __init +k2_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); + /* + * Check our hose index. If we are zero then we are on the + * local PCI hose, otherwise we are on the cPCI hose. + */ + if (!hose->index) { + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {1, 0, 0, 0}, /* Ethernet */ + {5, 5, 5, 5}, /* PMC Site 1 */ + {6, 6, 6, 6}, /* PMC Site 2 */ + {0, 0, 0, 0}, /* unused */ + {0, 0, 0, 0}, /* unused */ + {0, 0, 0, 0}, /* PCI-ISA Bridge */ + {0, 0, 0, 0}, /* unused */ + {0, 0, 0, 0}, /* unused */ + {0, 0, 0, 0}, /* unused */ + {0, 0, 0, 0}, /* unused */ + {0, 0, 0, 0}, /* unused */ + {0, 0, 0, 0}, /* unused */ + {0, 0, 0, 0}, /* unused */ + {0, 0, 0, 0}, /* unused */ + {15, 0, 0, 0}, /* M5229 IDE */ + }; + const long min_idsel = 3, max_idsel = 17, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; + } else { + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {10, 11, 12, 9}, /* cPCI slot 8 */ + {11, 12, 9, 10}, /* cPCI slot 7 */ + {12, 9, 10, 11}, /* cPCI slot 6 */ + {9, 10, 11, 12}, /* cPCI slot 5 */ + {10, 11, 12, 9}, /* cPCI slot 4 */ + {11, 12, 9, 10}, /* cPCI slot 3 */ + {12, 9, 10, 11}, /* cPCI slot 2 */ + }; + const long min_idsel = 15, max_idsel = 21, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; + } +} + +void k2_pcibios_fixup(void) +{ +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) + struct pci_dev *ide_dev; + + /* + * Enable DMA support on hdc + */ + ide_dev = pci_get_device(PCI_VENDOR_ID_AL, + PCI_DEVICE_ID_AL_M5229, NULL); + + if (ide_dev) { + + unsigned long ide_dma_base; + + ide_dma_base = pci_resource_start(ide_dev, 4); + outb(0x00, ide_dma_base + 0x2); + outb(0x20, ide_dma_base + 0xa); + pci_dev_put(ide_dev); + } +#endif +} + +void k2_pcibios_fixup_resources(struct pci_dev *dev) +{ + int i; + + if ((dev->vendor == PCI_VENDOR_ID_IBM) && + (dev->device == PCI_DEVICE_ID_IBM_CPC710_PCI64)) { + pr_debug("Fixup CPC710 resources\n"); + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { + dev->resource[i].start = 0; + dev->resource[i].end = 0; + } + } +} + +void k2_setup_hoses(void) +{ + struct pci_controller *hose_a, *hose_b; + + /* + * Reconfigure CPC710 memory map so + * we have some more PCI memory space. + */ + + /* Set FPHB mode */ + __raw_writel(0x808000e0, PGCHP); /* Set FPHB mode */ + + /* PCI32 mappings */ + __raw_writel(0x00000000, K2_PCI32_BAR + PIBAR); /* PCI I/O base */ + __raw_writel(0x00000000, K2_PCI32_BAR + PMBAR); /* PCI Mem base */ + __raw_writel(0xf0000000, K2_PCI32_BAR + MSIZE); /* 256MB */ + __raw_writel(0xfff00000, K2_PCI32_BAR + IOSIZE); /* 1MB */ + __raw_writel(0xc0000000, K2_PCI32_BAR + SMBAR); /* Base@0xc0000000 */ + __raw_writel(0x80000000, K2_PCI32_BAR + SIBAR); /* Base@0x80000000 */ + __raw_writel(0x000000c0, K2_PCI32_BAR + PSSIZE); /* 1GB space */ + __raw_writel(0x000000c0, K2_PCI32_BAR + PPSIZE); /* 1GB space */ + __raw_writel(0x00000000, K2_PCI32_BAR + BARPS); /* Base@0x00000000 */ + __raw_writel(0x00000000, K2_PCI32_BAR + BARPP); /* Base@0x00000000 */ + __raw_writel(0x00000080, K2_PCI32_BAR + PSBAR); /* Base@0x80 */ + __raw_writel(0x00000000, K2_PCI32_BAR + PPBAR); + + __raw_writel(0xc0000000, K2_PCI32_BAR + BPMDLK); + __raw_writel(0xd0000000, K2_PCI32_BAR + TPMDLK); + __raw_writel(0x80000000, K2_PCI32_BAR + BIODLK); + __raw_writel(0x80100000, K2_PCI32_BAR + TIODLK); + __raw_writel(0xe0008000, K2_PCI32_BAR + DLKCTRL); + __raw_writel(0xffffffff, K2_PCI32_BAR + DLKDEV); + + /* PCI64 mappings */ + __raw_writel(0x00100000, K2_PCI64_BAR + PIBAR); /* PCI I/O base */ + __raw_writel(0x10000000, K2_PCI64_BAR + PMBAR); /* PCI Mem base */ + __raw_writel(0xf0000000, K2_PCI64_BAR + MSIZE); /* 256MB */ + __raw_writel(0xfff00000, K2_PCI64_BAR + IOSIZE); /* 1MB */ + __raw_writel(0xd0000000, K2_PCI64_BAR + SMBAR); /* Base@0xd0000000 */ + __raw_writel(0x80100000, K2_PCI64_BAR + SIBAR); /* Base@0x80100000 */ + __raw_writel(0x000000c0, K2_PCI64_BAR + PSSIZE); /* 1GB space */ + __raw_writel(0x000000c0, K2_PCI64_BAR + PPSIZE); /* 1GB space */ + __raw_writel(0x00000000, K2_PCI64_BAR + BARPS); /* Base@0x00000000 */ + __raw_writel(0x00000000, K2_PCI64_BAR + BARPP); /* Base@0x00000000 */ + + /* Setup PCI32 hose */ + hose_a = pcibios_alloc_controller(); + if (!hose_a) + return; + + hose_a->first_busno = 0; + hose_a->last_busno = 0xff; + hose_a->pci_mem_offset = K2_PCI32_MEM_BASE; + + pci_init_resource(&hose_a->io_resource, + K2_PCI32_LOWER_IO, + K2_PCI32_UPPER_IO, + IORESOURCE_IO, "PCI32 host bridge"); + + pci_init_resource(&hose_a->mem_resources[0], + K2_PCI32_LOWER_MEM + K2_PCI32_MEM_BASE, + K2_PCI32_UPPER_MEM + K2_PCI32_MEM_BASE, + IORESOURCE_MEM, "PCI32 host bridge"); + + hose_a->io_space.start = K2_PCI32_LOWER_IO; + hose_a->io_space.end = K2_PCI32_UPPER_IO; + hose_a->mem_space.start = K2_PCI32_LOWER_MEM; + hose_a->mem_space.end = K2_PCI32_UPPER_MEM; + hose_a->io_base_virt = (void *)K2_ISA_IO_BASE; + + setup_indirect_pci(hose_a, K2_PCI32_CONFIG_ADDR, K2_PCI32_CONFIG_DATA); + + /* Initialize PCI32 bus registers */ + early_write_config_byte(hose_a, + hose_a->first_busno, + PCI_DEVFN(0, 0), + CPC710_BUS_NUMBER, hose_a->first_busno); + + early_write_config_byte(hose_a, + hose_a->first_busno, + PCI_DEVFN(0, 0), + CPC710_SUB_BUS_NUMBER, hose_a->last_busno); + + /* Enable PCI interrupt polling */ + early_write_config_byte(hose_a, + hose_a->first_busno, + PCI_DEVFN(8, 0), 0x45, 0x80); + + /* Route polled PCI interrupts */ + early_write_config_byte(hose_a, + hose_a->first_busno, + PCI_DEVFN(8, 0), 0x48, 0x58); + + early_write_config_byte(hose_a, + hose_a->first_busno, + PCI_DEVFN(8, 0), 0x49, 0x07); + + early_write_config_byte(hose_a, + hose_a->first_busno, + PCI_DEVFN(8, 0), 0x4a, 0x31); + + early_write_config_byte(hose_a, + hose_a->first_busno, + PCI_DEVFN(8, 0), 0x4b, 0xb9); + + /* route secondary IDE channel interrupt to IRQ 15 */ + early_write_config_byte(hose_a, + hose_a->first_busno, + PCI_DEVFN(8, 0), 0x75, 0x0f); + + /* enable IDE controller IDSEL */ + early_write_config_byte(hose_a, + hose_a->first_busno, + PCI_DEVFN(8, 0), 0x58, 0x48); + + /* Enable IDE function */ + early_write_config_byte(hose_a, + hose_a->first_busno, + PCI_DEVFN(17, 0), 0x50, 0x03); + + /* Set M5229 IDE controller to native mode */ + early_write_config_byte(hose_a, + hose_a->first_busno, + PCI_DEVFN(17, 0), PCI_CLASS_PROG, 0xdf); + + hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno); + + /* Write out correct max subordinate bus number for hose A */ + early_write_config_byte(hose_a, + hose_a->first_busno, + PCI_DEVFN(0, 0), + CPC710_SUB_BUS_NUMBER, hose_a->last_busno); + + /* Only setup PCI64 hose if we are in the system slot */ + if (!(readb(K2_MISC_REG) & K2_SYS_SLOT_MASK)) { + /* Setup PCI64 hose */ + hose_b = pcibios_alloc_controller(); + if (!hose_b) + return; + + hose_b->first_busno = hose_a->last_busno + 1; + hose_b->last_busno = 0xff; + + /* Reminder: quit changing the following, it is correct. */ + hose_b->pci_mem_offset = K2_PCI32_MEM_BASE; + + pci_init_resource(&hose_b->io_resource, + K2_PCI64_LOWER_IO, + K2_PCI64_UPPER_IO, + IORESOURCE_IO, "PCI64 host bridge"); + + pci_init_resource(&hose_b->mem_resources[0], + K2_PCI64_LOWER_MEM + K2_PCI32_MEM_BASE, + K2_PCI64_UPPER_MEM + K2_PCI32_MEM_BASE, + IORESOURCE_MEM, "PCI64 host bridge"); + + hose_b->io_space.start = K2_PCI64_LOWER_IO; + hose_b->io_space.end = K2_PCI64_UPPER_IO; + hose_b->mem_space.start = K2_PCI64_LOWER_MEM; + hose_b->mem_space.end = K2_PCI64_UPPER_MEM; + hose_b->io_base_virt = (void *)K2_ISA_IO_BASE; + + setup_indirect_pci(hose_b, + K2_PCI64_CONFIG_ADDR, K2_PCI64_CONFIG_DATA); + + /* Initialize PCI64 bus registers */ + early_write_config_byte(hose_b, + 0, + PCI_DEVFN(0, 0), + CPC710_SUB_BUS_NUMBER, 0xff); + + early_write_config_byte(hose_b, + 0, + PCI_DEVFN(0, 0), + CPC710_BUS_NUMBER, hose_b->first_busno); + + hose_b->last_busno = pciauto_bus_scan(hose_b, + hose_b->first_busno); + + /* Write out correct max subordinate bus number for hose B */ + early_write_config_byte(hose_b, + hose_b->first_busno, + PCI_DEVFN(0, 0), + CPC710_SUB_BUS_NUMBER, + hose_b->last_busno); + + /* Configure PCI64 PSBAR */ + early_write_config_dword(hose_b, + hose_b->first_busno, + PCI_DEVFN(0, 0), + PCI_BASE_ADDRESS_0, + K2_PCI64_SYS_MEM_BASE); + } + + /* Configure i8259 level/edge settings */ + outb(0x62, 0x4d0); + outb(0xde, 0x4d1); + +#ifdef CONFIG_CPC710_DATA_GATHERING + { + unsigned int tmp; + tmp = __raw_readl(ABCNTL); + /* Enable data gathering on both PCI interfaces */ + __raw_writel(tmp | 0x05000000, ABCNTL); + } +#endif + + ppc_md.pcibios_fixup = k2_pcibios_fixup; + ppc_md.pcibios_fixup_resources = k2_pcibios_fixup_resources; + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = k2_map_irq; +} + +static int k2_get_bus_speed(void) +{ + int bus_speed; + unsigned char board_id; + + board_id = *(unsigned char *)K2_BOARD_ID_REG; + + switch (K2_BUS_SPD(board_id)) { + + case 0: + default: + bus_speed = 100000000; + break; + + case 1: + bus_speed = 83333333; + break; + + case 2: + bus_speed = 75000000; + break; + + case 3: + bus_speed = 66666666; + break; + } + return bus_speed; +} + +static int k2_get_cpu_speed(void) +{ + unsigned long hid1; + int cpu_speed; + + hid1 = mfspr(SPRN_HID1) >> 28; + + if ((mfspr(SPRN_PVR) >> 16) == 8) + hid1 = cpu_7xx[hid1]; + else + hid1 = cpu_6xx[hid1]; + + cpu_speed = k2_get_bus_speed() * hid1 / 2; + return cpu_speed; +} + +static void __init k2_calibrate_decr(void) +{ + int freq, divisor = 4; + + /* determine processor bus speed */ + freq = k2_get_bus_speed(); + tb_ticks_per_jiffy = freq / HZ / divisor; + tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000); +} + +static int k2_show_cpuinfo(struct seq_file *m) +{ + unsigned char k2_geo_bits, k2_system_slot; + + seq_printf(m, "vendor\t\t: SBS\n"); + seq_printf(m, "machine\t\t: K2\n"); + seq_printf(m, "cpu speed\t: %dMhz\n", k2_get_cpu_speed() / 1000000); + seq_printf(m, "bus speed\t: %dMhz\n", k2_get_bus_speed() / 1000000); + seq_printf(m, "memory type\t: SDRAM\n"); + + k2_geo_bits = readb(K2_MSIZ_GEO_REG) & K2_GEO_ADR_MASK; + k2_system_slot = !(readb(K2_MISC_REG) & K2_SYS_SLOT_MASK); + seq_printf(m, "backplane\t: %s slot board", + k2_system_slot ? "System" : "Non system"); + seq_printf(m, "with geographical address %x\n", k2_geo_bits); + + return 0; +} + +TODC_ALLOC(); + +static void __init k2_setup_arch(void) +{ + unsigned int cpu; + + /* Setup TODC access */ + TODC_INIT(TODC_TYPE_MK48T37, 0, 0, + ioremap(K2_RTC_BASE_ADDRESS, K2_RTC_SIZE), 8); + + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000 / HZ; + + /* make FLASH transactions higher priority than PCI to avoid deadlock */ + __raw_writel(__raw_readl(SIOC1) | 0x80000000, SIOC1); + + /* Set hardware to access FLASH page 2 */ + __raw_writel(1 << 29, GPOUT); + + /* Setup PCI host bridges */ + k2_setup_hoses(); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_HDC1; +#endif + + /* Identify the system */ + printk(KERN_INFO "System Identification: SBS K2 - PowerPC 750 @ " + "%d Mhz\n", k2_get_cpu_speed() / 1000000); + printk(KERN_INFO "Port by MontaVista Software, Inc. " + "(source@mvista.com)\n"); + + /* Identify the CPU manufacturer */ + cpu = PVR_REV(mfspr(SPRN_PVR)); + printk(KERN_INFO "CPU manufacturer: %s [rev=%04x]\n", + (cpu & (1 << 15)) ? "IBM" : "Motorola", cpu); +} + +static void k2_restart(char *cmd) +{ + local_irq_disable(); + + /* Flip FLASH back to page 1 to access firmware image */ + __raw_writel(0, GPOUT); + + /* SRR0 has system reset vector, SRR1 has default MSR value */ + /* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */ + mtspr(SPRN_SRR0, 0xfff00100); + mtspr(SPRN_SRR1, 0); + __asm__ __volatile__("rfi\n\t"); + + /* not reached */ + for (;;) ; +} + +static void k2_power_off(void) +{ + for (;;) ; +} + +static void k2_halt(void) +{ + k2_restart(NULL); +} + +/* + * Set BAT 3 to map PCI32 I/O space. + */ +static __inline__ void k2_set_bat(void) +{ + /* wait for all outstanding memory accesses to complete */ + mb(); + + /* setup DBATs */ + mtspr(SPRN_DBAT2U, 0x80001ffe); + mtspr(SPRN_DBAT2L, 0x8000002a); + mtspr(SPRN_DBAT3U, 0xf0001ffe); + mtspr(SPRN_DBAT3L, 0xf000002a); + + /* wait for updates */ + mb(); +} + +static unsigned long __init k2_find_end_of_memory(void) +{ + unsigned long total; + unsigned char msize = 7; /* Default to 128MB */ + + msize = K2_MEM_SIZE(readb(K2_MSIZ_GEO_REG)); + + switch (msize) { + case 2: + /* + * This will break without a lowered + * KERNELBASE or CONFIG_HIGHMEM on. + * It seems non 1GB builds exist yet, + * though. + */ + total = K2_MEM_SIZE_1GB; + break; + case 3: + case 4: + total = K2_MEM_SIZE_512MB; + break; + case 5: + case 6: + total = K2_MEM_SIZE_256MB; + break; + case 7: + total = K2_MEM_SIZE_128MB; + break; + default: + printk + ("K2: Invalid memory size detected, defaulting to 128MB\n"); + total = K2_MEM_SIZE_128MB; + break; + } + return total; +} + +static void __init k2_map_io(void) +{ + io_block_mapping(K2_PCI32_IO_BASE, + K2_PCI32_IO_BASE, 0x00200000, _PAGE_IO); + io_block_mapping(0xff000000, 0xff000000, 0x01000000, _PAGE_IO); +} + +static void __init k2_init_irq(void) +{ + int i; + + for (i = 0; i < 16; i++) + irq_desc[i].handler = &i8259_pic; + + i8259_init(0); +} + +void __init platform_init(unsigned long r3, unsigned long r4, + unsigned long r5, unsigned long r6, unsigned long r7) +{ + parse_bootinfo((struct bi_record *)(r3 + KERNELBASE)); + + k2_set_bat(); + + isa_io_base = K2_ISA_IO_BASE; + isa_mem_base = K2_ISA_MEM_BASE; + pci_dram_offset = K2_PCI32_SYS_MEM_BASE; + + ppc_md.setup_arch = k2_setup_arch; + ppc_md.show_cpuinfo = k2_show_cpuinfo; + ppc_md.init_IRQ = k2_init_irq; + ppc_md.get_irq = i8259_irq; + + ppc_md.find_end_of_memory = k2_find_end_of_memory; + ppc_md.setup_io_mappings = k2_map_io; + + ppc_md.restart = k2_restart; + ppc_md.power_off = k2_power_off; + ppc_md.halt = k2_halt; + + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.calibrate_decr = k2_calibrate_decr; + + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; + +#ifdef CONFIG_SERIAL_TEXT_DEBUG + ppc_md.progress = gen550_progress; +#endif +} diff --git a/arch/ppc/platforms/k2.h b/arch/ppc/platforms/k2.h new file mode 100644 index 00000000000..78326aba198 --- /dev/null +++ b/arch/ppc/platforms/k2.h @@ -0,0 +1,82 @@ +/* + * arch/ppc/platforms/k2.h + * + * Definitions for SBS K2 board support + * + * Author: Matt Porter <mporter@mvista.com> + * + * 2001 (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. + */ + +#ifndef __PPC_PLATFORMS_K2_H +#define __PPC_PLATFORMS_K2_H + +/* + * SBS K2 definitions + */ + +#define K2_PCI64_BAR 0xff400000 +#define K2_PCI32_BAR 0xff500000 + +#define K2_PCI64_CONFIG_ADDR (K2_PCI64_BAR + 0x000f8000) +#define K2_PCI64_CONFIG_DATA (K2_PCI64_BAR + 0x000f8010) + +#define K2_PCI32_CONFIG_ADDR (K2_PCI32_BAR + 0x000f8000) +#define K2_PCI32_CONFIG_DATA (K2_PCI32_BAR + 0x000f8010) + +#define K2_PCI64_MEM_BASE 0xd0000000 +#define K2_PCI64_IO_BASE 0x80100000 + +#define K2_PCI32_MEM_BASE 0xc0000000 +#define K2_PCI32_IO_BASE 0x80000000 + +#define K2_PCI32_SYS_MEM_BASE 0x80000000 +#define K2_PCI64_SYS_MEM_BASE K2_PCI32_SYS_MEM_BASE + +#define K2_PCI32_LOWER_MEM 0x00000000 +#define K2_PCI32_UPPER_MEM 0x0fffffff +#define K2_PCI32_LOWER_IO 0x00000000 +#define K2_PCI32_UPPER_IO 0x000fffff + +#define K2_PCI64_LOWER_MEM 0x10000000 +#define K2_PCI64_UPPER_MEM 0x1fffffff +#define K2_PCI64_LOWER_IO 0x00100000 +#define K2_PCI64_UPPER_IO 0x001fffff + +#define K2_ISA_IO_BASE K2_PCI32_IO_BASE +#define K2_ISA_MEM_BASE K2_PCI32_MEM_BASE + +#define K2_BOARD_ID_REG (K2_ISA_IO_BASE + 0x800) +#define K2_MISC_REG (K2_ISA_IO_BASE + 0x804) +#define K2_MSIZ_GEO_REG (K2_ISA_IO_BASE + 0x808) +#define K2_HOT_SWAP_REG (K2_ISA_IO_BASE + 0x80c) +#define K2_PLD2_REG (K2_ISA_IO_BASE + 0x80e) +#define K2_PLD3_REG (K2_ISA_IO_BASE + 0x80f) + +#define K2_BUS_SPD(board_id) (board_id >> 2) & 3 + +#define K2_RTC_BASE_OFFSET 0x90000 +#define K2_RTC_BASE_ADDRESS (K2_PCI32_MEM_BASE + K2_RTC_BASE_OFFSET) +#define K2_RTC_SIZE 0x8000 + +#define K2_MEM_SIZE_MASK 0xe0 +#define K2_MEM_SIZE(size_reg) (size_reg & K2_MEM_SIZE_MASK) >> 5 +#define K2_MEM_SIZE_1GB 0x40000000 +#define K2_MEM_SIZE_512MB 0x20000000 +#define K2_MEM_SIZE_256MB 0x10000000 +#define K2_MEM_SIZE_128MB 0x08000000 + +#define K2_L2CACHE_MASK 0x03 /* Mask for 2 L2 Cache bits */ +#define K2_L2CACHE_512KB 0x00 /* 512KB */ +#define K2_L2CACHE_256KB 0x01 /* 256KB */ +#define K2_L2CACHE_1MB 0x02 /* 1MB */ +#define K2_L2CACHE_NONE 0x03 /* None */ + +#define K2_GEO_ADR_MASK 0x1f + +#define K2_SYS_SLOT_MASK 0x08 + +#endif /* __PPC_PLATFORMS_K2_H */ diff --git a/arch/ppc/platforms/katana.c b/arch/ppc/platforms/katana.c new file mode 100644 index 00000000000..eda922ac316 --- /dev/null +++ b/arch/ppc/platforms/katana.c @@ -0,0 +1,795 @@ +/* + * arch/ppc/platforms/katana.c + * + * Board setup routines for the Artesyn Katana cPCI boards. + * + * Author: Tim Montgomery <timm@artesyncp.com> + * Maintained by: Mark A. Greer <mgreer@mvista.com> + * + * Based on code done by Rabeeh Khoury - rabeeh@galileo.co.il + * Based on code done by - Mark A. Greer <mgreer@mvista.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +/* + * Supports the Artesyn 750i, 752i, and 3750. The 752i is virtually identical + * to the 750i except that it has an mv64460 bridge. + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/console.h> +#include <linux/initrd.h> +#include <linux/root_dev.h> +#include <linux/delay.h> +#include <linux/seq_file.h> +#include <linux/bootmem.h> +#include <linux/mtd/physmap.h> +#include <linux/mv643xx.h> +#ifdef CONFIG_BOOTIMG +#include <linux/bootimg.h> +#endif +#include <asm/page.h> +#include <asm/time.h> +#include <asm/smp.h> +#include <asm/todc.h> +#include <asm/bootinfo.h> +#include <asm/ppcboot.h> +#include <asm/mv64x60.h> +#include <platforms/katana.h> + +static struct mv64x60_handle bh; +static katana_id_t katana_id; +static void __iomem *cpld_base; +static void __iomem *sram_base; + +static u32 katana_flash_size_0; +static u32 katana_flash_size_1; + +static u32 katana_bus_frequency; + +unsigned char __res[sizeof(bd_t)]; + +/* PCI Interrupt routing */ +static int __init +katana_irq_lookup_750i(unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = { + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + /* IDSEL 4 (PMC 1) */ + { KATANA_PCI_INTB_IRQ_750i, KATANA_PCI_INTC_IRQ_750i, + KATANA_PCI_INTD_IRQ_750i, KATANA_PCI_INTA_IRQ_750i }, + /* IDSEL 5 (PMC 2) */ + { KATANA_PCI_INTC_IRQ_750i, KATANA_PCI_INTD_IRQ_750i, + KATANA_PCI_INTA_IRQ_750i, KATANA_PCI_INTB_IRQ_750i }, + /* IDSEL 6 (T8110) */ + {KATANA_PCI_INTD_IRQ_750i, 0, 0, 0 }, + }; + const long min_idsel = 4, max_idsel = 6, irqs_per_slot = 4; + + return PCI_IRQ_TABLE_LOOKUP; +} + +static int __init +katana_irq_lookup_3750(unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = { + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { KATANA_PCI_INTA_IRQ_3750, 0, 0, 0 }, /* IDSEL 3 (BCM5691) */ + { KATANA_PCI_INTB_IRQ_3750, 0, 0, 0 }, /* IDSEL 4 (MV64360 #2)*/ + { KATANA_PCI_INTC_IRQ_3750, 0, 0, 0 }, /* IDSEL 5 (MV64360 #3)*/ + }; + const long min_idsel = 3, max_idsel = 5, irqs_per_slot = 4; + + return PCI_IRQ_TABLE_LOOKUP; +} + +static int __init +katana_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + switch (katana_id) { + case KATANA_ID_750I: + case KATANA_ID_752I: + return katana_irq_lookup_750i(idsel, pin); + + case KATANA_ID_3750: + return katana_irq_lookup_3750(idsel, pin); + + default: + printk(KERN_ERR "Bogus board ID\n"); + return 0; + } +} + +/* Board info retrieval routines */ +void __init +katana_get_board_id(void) +{ + switch (in_8(cpld_base + KATANA_CPLD_PRODUCT_ID)) { + case KATANA_PRODUCT_ID_3750: + katana_id = KATANA_ID_3750; + break; + + case KATANA_PRODUCT_ID_750i: + katana_id = KATANA_ID_750I; + break; + + case KATANA_PRODUCT_ID_752i: + katana_id = KATANA_ID_752I; + break; + + default: + printk(KERN_ERR "Unsupported board\n"); + } +} + +int __init +katana_get_proc_num(void) +{ + u16 val; + u8 save_exclude; + static int proc = -1; + static u8 first_time = 1; + + if (first_time) { + if (katana_id != KATANA_ID_3750) + proc = 0; + else { + save_exclude = mv64x60_pci_exclude_bridge; + mv64x60_pci_exclude_bridge = 0; + + early_read_config_word(bh.hose_a, 0, + PCI_DEVFN(0,0), PCI_DEVICE_ID, &val); + + mv64x60_pci_exclude_bridge = save_exclude; + + switch(val) { + case PCI_DEVICE_ID_KATANA_3750_PROC0: + proc = 0; + break; + + case PCI_DEVICE_ID_KATANA_3750_PROC1: + proc = 1; + break; + + case PCI_DEVICE_ID_KATANA_3750_PROC2: + proc = 2; + break; + + default: + printk(KERN_ERR "Bogus Device ID\n"); + } + } + + first_time = 0; + } + + return proc; +} + +static inline int +katana_is_monarch(void) +{ + return in_8(cpld_base + KATANA_CPLD_BD_CFG_3) & + KATANA_CPLD_BD_CFG_3_MONARCH; +} + +static void __init +katana_setup_bridge(void) +{ + struct pci_controller hose; + struct mv64x60_setup_info si; + void __iomem *vaddr; + int i; + u16 val; + u8 save_exclude; + + /* + * Some versions of the Katana firmware mistakenly change the vendor + * & device id fields in the bridge's pci device (visible via pci + * config accesses). This breaks mv64x60_init() because those values + * are used to identify the type of bridge that's there. Artesyn + * claims that the subsystem vendor/device id's will have the correct + * Marvell values so this code puts back the correct values from there. + */ + memset(&hose, 0, sizeof(hose)); + vaddr = ioremap(CONFIG_MV64X60_NEW_BASE, MV64x60_INTERNAL_SPACE_SIZE); + setup_indirect_pci_nomap(&hose, vaddr + MV64x60_PCI0_CONFIG_ADDR, + vaddr + MV64x60_PCI0_CONFIG_DATA); + save_exclude = mv64x60_pci_exclude_bridge; + mv64x60_pci_exclude_bridge = 0; + + early_read_config_word(&hose, 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID, &val); + + if (val != PCI_VENDOR_ID_MARVELL) { + early_read_config_word(&hose, 0, PCI_DEVFN(0, 0), + PCI_SUBSYSTEM_VENDOR_ID, &val); + early_write_config_word(&hose, 0, PCI_DEVFN(0, 0), + PCI_VENDOR_ID, val); + early_read_config_word(&hose, 0, PCI_DEVFN(0, 0), + PCI_SUBSYSTEM_ID, &val); + early_write_config_word(&hose, 0, PCI_DEVFN(0, 0), + PCI_DEVICE_ID, val); + } + + mv64x60_pci_exclude_bridge = save_exclude; + iounmap(vaddr); + + memset(&si, 0, sizeof(si)); + + si.phys_reg_base = CONFIG_MV64X60_NEW_BASE; + + si.pci_1.enable_bus = 1; + si.pci_1.pci_io.cpu_base = KATANA_PCI1_IO_START_PROC_ADDR; + si.pci_1.pci_io.pci_base_hi = 0; + si.pci_1.pci_io.pci_base_lo = KATANA_PCI1_IO_START_PCI_ADDR; + si.pci_1.pci_io.size = KATANA_PCI1_IO_SIZE; + si.pci_1.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE; + si.pci_1.pci_mem[0].cpu_base = KATANA_PCI1_MEM_START_PROC_ADDR; + si.pci_1.pci_mem[0].pci_base_hi = KATANA_PCI1_MEM_START_PCI_HI_ADDR; + si.pci_1.pci_mem[0].pci_base_lo = KATANA_PCI1_MEM_START_PCI_LO_ADDR; + si.pci_1.pci_mem[0].size = KATANA_PCI1_MEM_SIZE; + si.pci_1.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE; + si.pci_1.pci_cmd_bits = 0; + si.pci_1.latency_timer = 0x80; + + for (i = 0; i < MV64x60_CPU2MEM_WINDOWS; i++) { +#if defined(CONFIG_NOT_COHERENT_CACHE) + si.cpu_prot_options[i] = 0; + si.enet_options[i] = MV64360_ENET2MEM_SNOOP_NONE; + si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_NONE; + si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE; + + si.pci_1.acc_cntl_options[i] = + MV64360_PCI_ACC_CNTL_SNOOP_NONE | + MV64360_PCI_ACC_CNTL_SWAP_NONE | + MV64360_PCI_ACC_CNTL_MBURST_128_BYTES | + MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES; +#else + si.cpu_prot_options[i] = 0; + si.enet_options[i] = MV64360_ENET2MEM_SNOOP_NONE; /* errata */ + si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_NONE; /* errata */ + si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE; /* errata */ + + si.pci_1.acc_cntl_options[i] = + MV64360_PCI_ACC_CNTL_SNOOP_WB | + MV64360_PCI_ACC_CNTL_SWAP_NONE | + MV64360_PCI_ACC_CNTL_MBURST_32_BYTES | + MV64360_PCI_ACC_CNTL_RDSIZE_32_BYTES; +#endif + } + + /* Lookup PCI host bridges */ + if (mv64x60_init(&bh, &si)) + printk(KERN_WARNING "Bridge initialization failed.\n"); + + pci_dram_offset = 0; /* sys mem at same addr on PCI & cpu bus */ + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = katana_map_irq; + ppc_md.pci_exclude_device = mv64x60_pci_exclude_device; + + mv64x60_set_bus(&bh, 1, 0); + bh.hose_b->first_busno = 0; + bh.hose_b->last_busno = 0xff; +} + +/* Bridge & platform setup routines */ +void __init +katana_intr_setup(void) +{ + /* MPP 8, 9, and 10 */ + mv64x60_clr_bits(&bh, MV64x60_MPP_CNTL_1, 0xfff); + + /* MPP 14 */ + if ((katana_id == KATANA_ID_750I) || (katana_id == KATANA_ID_752I)) + mv64x60_clr_bits(&bh, MV64x60_MPP_CNTL_1, 0x0f000000); + + /* + * Define GPP 8,9,and 10 interrupt polarity as active low + * input signal and level triggered + */ + mv64x60_set_bits(&bh, MV64x60_GPP_LEVEL_CNTL, 0x700); + mv64x60_clr_bits(&bh, MV64x60_GPP_IO_CNTL, 0x700); + + if ((katana_id == KATANA_ID_750I) || (katana_id == KATANA_ID_752I)) { + mv64x60_set_bits(&bh, MV64x60_GPP_LEVEL_CNTL, (1<<14)); + mv64x60_clr_bits(&bh, MV64x60_GPP_IO_CNTL, (1<<14)); + } + + /* Config GPP intr ctlr to respond to level trigger */ + mv64x60_set_bits(&bh, MV64x60_COMM_ARBITER_CNTL, (1<<10)); + + /* Erranum FEr PCI-#8 */ + mv64x60_clr_bits(&bh, MV64x60_PCI0_CMD, (1<<5) | (1<<9)); + mv64x60_clr_bits(&bh, MV64x60_PCI1_CMD, (1<<5) | (1<<9)); + + /* + * Dismiss and then enable interrupt on GPP interrupt cause + * for CPU #0 + */ + mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, ~0x700); + mv64x60_set_bits(&bh, MV64x60_GPP_INTR_MASK, 0x700); + + if ((katana_id == KATANA_ID_750I) || (katana_id == KATANA_ID_752I)) { + mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, ~(1<<14)); + mv64x60_set_bits(&bh, MV64x60_GPP_INTR_MASK, (1<<14)); + } + + /* + * Dismiss and then enable interrupt on CPU #0 high cause reg + * BIT25 summarizes GPP interrupts 8-15 + */ + mv64x60_set_bits(&bh, MV64360_IC_CPU0_INTR_MASK_HI, (1<<25)); +} + +void __init +katana_setup_peripherals(void) +{ + u32 base; + + /* Set up windows for boot CS, soldered & socketed flash, and CPLD */ + mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN, + KATANA_BOOT_WINDOW_BASE, KATANA_BOOT_WINDOW_SIZE, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN); + + /* Assume firmware set up window sizes correctly for dev 0 & 1 */ + mv64x60_get_32bit_window(&bh, MV64x60_CPU2DEV_0_WIN, &base, + &katana_flash_size_0); + + if (katana_flash_size_0 > 0) { + mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_0_WIN, + KATANA_SOLDERED_FLASH_BASE, katana_flash_size_0, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_0_WIN); + } + + mv64x60_get_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN, &base, + &katana_flash_size_1); + + if (katana_flash_size_1 > 0) { + mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN, + (KATANA_SOLDERED_FLASH_BASE + katana_flash_size_0), + katana_flash_size_1, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_1_WIN); + } + + mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_2_WIN, + KATANA_SOCKET_BASE, KATANA_SOCKETED_FLASH_SIZE, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_2_WIN); + + mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_3_WIN, + KATANA_CPLD_BASE, KATANA_CPLD_SIZE, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_3_WIN); + cpld_base = ioremap(KATANA_CPLD_BASE, KATANA_CPLD_SIZE); + + mv64x60_set_32bit_window(&bh, MV64x60_CPU2SRAM_WIN, + KATANA_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN); + sram_base = ioremap(KATANA_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE); + + /* Set up Enet->SRAM window */ + mv64x60_set_32bit_window(&bh, MV64x60_ENET2MEM_4_WIN, + KATANA_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE, 0x2); + bh.ci->enable_window_32bit(&bh, MV64x60_ENET2MEM_4_WIN); + + /* Give enet r/w access to memory region */ + mv64x60_set_bits(&bh, MV64360_ENET2MEM_ACC_PROT_0, (0x3 << (4 << 1))); + mv64x60_set_bits(&bh, MV64360_ENET2MEM_ACC_PROT_1, (0x3 << (4 << 1))); + mv64x60_set_bits(&bh, MV64360_ENET2MEM_ACC_PROT_2, (0x3 << (4 << 1))); + + mv64x60_clr_bits(&bh, MV64x60_PCI1_PCI_DECODE_CNTL, (1 << 3)); + mv64x60_clr_bits(&bh, MV64x60_TIMR_CNTR_0_3_CNTL, + ((1 << 0) | (1 << 8) | (1 << 16) | (1 << 24))); + + /* Must wait until window set up before retrieving board id */ + katana_get_board_id(); + + /* Enumerate pci bus (must know board id before getting proc number) */ + if (katana_get_proc_num() == 0) + bh.hose_b->last_busno = pciauto_bus_scan(bh.hose_b, 0); + +#if defined(CONFIG_NOT_COHERENT_CACHE) + mv64x60_write(&bh, MV64360_SRAM_CONFIG, 0x00160000); +#else + mv64x60_write(&bh, MV64360_SRAM_CONFIG, 0x001600b2); +#endif + + /* + * Setting the SRAM to 0. Note that this generates parity errors on + * internal data path in SRAM since it's first time accessing it + * while after reset it's not configured. + */ + memset(sram_base, 0, MV64360_SRAM_SIZE); + + /* Only processor zero [on 3750] is an PCI interrupt controller */ + if (katana_get_proc_num() == 0) + katana_intr_setup(); +} + +static void __init +katana_enable_ipmi(void) +{ + u8 reset_out; + + /* Enable access to IPMI ctlr by clearing IPMI PORTSEL bit in CPLD */ + reset_out = in_8(cpld_base + KATANA_CPLD_RESET_OUT); + reset_out &= ~KATANA_CPLD_RESET_OUT_PORTSEL; + out_8(cpld_base + KATANA_CPLD_RESET_OUT, reset_out); +} + +static void __init +katana_setup_arch(void) +{ + if (ppc_md.progress) + ppc_md.progress("katana_setup_arch: enter", 0); + + set_tb(0, 0); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_SDA2; +#endif + + /* + * Set up the L2CR register. + * + * 750FX has only L2E, L2PE (bits 2-8 are reserved) + * DD2.0 has bug that requires the L2 to be in WRT mode + * avoid dirty data in cache + */ + if (PVR_REV(mfspr(SPRN_PVR)) == 0x0200) { + printk(KERN_INFO "DD2.0 detected. Setting L2 cache" + "to Writethrough mode\n"); + _set_L2CR(L2CR_L2E | L2CR_L2PE | L2CR_L2WT); + } else + _set_L2CR(L2CR_L2E | L2CR_L2PE); + + if (ppc_md.progress) + ppc_md.progress("katana_setup_arch: calling setup_bridge", 0); + + katana_setup_bridge(); + katana_setup_peripherals(); + katana_enable_ipmi(); + + katana_bus_frequency = katana_bus_freq(cpld_base); + + printk(KERN_INFO "Artesyn Communication Products, LLC - Katana(TM)\n"); + if (ppc_md.progress) + ppc_md.progress("katana_setup_arch: exit", 0); +} + +/* Platform device data fixup routines. */ +#if defined(CONFIG_SERIAL_MPSC) +static void __init +katana_fixup_mpsc_pdata(struct platform_device *pdev) +{ + struct mpsc_pdata *pdata; + + pdata = (struct mpsc_pdata *)pdev->dev.platform_data; + + pdata->max_idle = 40; + pdata->default_baud = KATANA_DEFAULT_BAUD; + pdata->brg_clk_src = KATANA_MPSC_CLK_SRC; + /* + * TCLK (not SysCLk) is routed to BRG, then to the MPSC. On most parts, + * TCLK == SysCLK but on 64460, they are separate pins. + * SysCLK can go up to 200 MHz but TCLK can only go up to 133 MHz. + */ + pdata->brg_clk_freq = min(katana_bus_frequency, MV64x60_TCLK_FREQ_MAX); +} +#endif + +#if defined(CONFIG_MV643XX_ETH) +static void __init +katana_fixup_eth_pdata(struct platform_device *pdev) +{ + struct mv643xx_eth_platform_data *eth_pd; + static u16 phy_addr[] = { + KATANA_ETH0_PHY_ADDR, + KATANA_ETH1_PHY_ADDR, + KATANA_ETH2_PHY_ADDR, + }; + + eth_pd = pdev->dev.platform_data; + eth_pd->force_phy_addr = 1; + eth_pd->phy_addr = phy_addr[pdev->id]; + eth_pd->tx_queue_size = KATANA_ETH_TX_QUEUE_SIZE; + eth_pd->rx_queue_size = KATANA_ETH_RX_QUEUE_SIZE; +} +#endif + +static int __init +katana_platform_notify(struct device *dev) +{ + static struct { + char *bus_id; + void ((*rtn)(struct platform_device *pdev)); + } dev_map[] = { +#if defined(CONFIG_SERIAL_MPSC) + { MPSC_CTLR_NAME ".0", katana_fixup_mpsc_pdata }, + { MPSC_CTLR_NAME ".1", katana_fixup_mpsc_pdata }, +#endif +#if defined(CONFIG_MV643XX_ETH) + { MV643XX_ETH_NAME ".0", katana_fixup_eth_pdata }, + { MV643XX_ETH_NAME ".1", katana_fixup_eth_pdata }, + { MV643XX_ETH_NAME ".2", katana_fixup_eth_pdata }, +#endif + }; + struct platform_device *pdev; + int i; + + if (dev && dev->bus_id) + for (i=0; i<ARRAY_SIZE(dev_map); i++) + if (!strncmp(dev->bus_id, dev_map[i].bus_id, + BUS_ID_SIZE)) { + + pdev = container_of(dev, + struct platform_device, dev); + dev_map[i].rtn(pdev); + } + + return 0; +} + +#ifdef CONFIG_MTD_PHYSMAP + +#ifndef MB +#define MB (1 << 20) +#endif + +/* + * MTD Layout depends on amount of soldered FLASH in system. Sizes in MB. + * + * FLASH Amount: 128 64 32 16 + * ------------- --- -- -- -- + * Monitor: 1 1 1 1 + * Primary Kernel: 1.5 1.5 1.5 1.5 + * Primary fs: 30 30 <end> <end> + * Secondary Kernel: 1.5 1.5 N/A N/A + * Secondary fs: <end> <end> N/A N/A + * User: <overlays entire FLASH except for "Monitor" section> + */ +static int __init +katana_setup_mtd(void) +{ + u32 size; + int ptbl_entries; + static struct mtd_partition *ptbl; + + size = katana_flash_size_0 + katana_flash_size_1; + if (!size) + return -ENOMEM; + + ptbl_entries = (size >= (64*MB)) ? 6 : 4; + + if ((ptbl = kmalloc(ptbl_entries * sizeof(struct mtd_partition), + GFP_KERNEL)) == NULL) { + + printk(KERN_WARNING "Can't alloc MTD partition table\n"); + return -ENOMEM; + } + memset(ptbl, 0, ptbl_entries * sizeof(struct mtd_partition)); + + ptbl[0].name = "Monitor"; + ptbl[0].size = KATANA_MTD_MONITOR_SIZE; + ptbl[1].name = "Primary Kernel"; + ptbl[1].offset = MTDPART_OFS_NXTBLK; + ptbl[1].size = 0x00180000; /* 1.5 MB */ + ptbl[2].name = "Primary Filesystem"; + ptbl[2].offset = MTDPART_OFS_APPEND; + ptbl[2].size = MTDPART_SIZ_FULL; /* Correct for 16 & 32 MB */ + ptbl[ptbl_entries-1].name = "User FLASH"; + ptbl[ptbl_entries-1].offset = KATANA_MTD_MONITOR_SIZE; + ptbl[ptbl_entries-1].size = MTDPART_SIZ_FULL; + + if (size >= (64*MB)) { + ptbl[2].size = 30*MB; + ptbl[3].name = "Secondary Kernel"; + ptbl[3].offset = MTDPART_OFS_NXTBLK; + ptbl[3].size = 0x00180000; /* 1.5 MB */ + ptbl[4].name = "Secondary Filesystem"; + ptbl[4].offset = MTDPART_OFS_APPEND; + ptbl[4].size = MTDPART_SIZ_FULL; + } + + physmap_map.size = size; + physmap_set_partitions(ptbl, ptbl_entries); + return 0; +} + +arch_initcall(katana_setup_mtd); +#endif + +static void +katana_restart(char *cmd) +{ + ulong i = 10000000; + + /* issue hard reset to the reset command register */ + out_8(cpld_base + KATANA_CPLD_RST_CMD, KATANA_CPLD_RST_CMD_HR); + + while (i-- > 0) ; + panic("restart failed\n"); +} + +static void +katana_halt(void) +{ + u8 v; + + if (katana_id == KATANA_ID_752I) { + v = in_8(cpld_base + HSL_PLD_BASE + HSL_PLD_HOT_SWAP_OFF); + v |= HSL_PLD_HOT_SWAP_LED_BIT; + out_8(cpld_base + HSL_PLD_BASE + HSL_PLD_HOT_SWAP_OFF, v); + } + + while (1) ; + /* NOTREACHED */ +} + +static void +katana_power_off(void) +{ + katana_halt(); + /* NOTREACHED */ +} + +static int +katana_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "vendor\t\t: Artesyn Communication Products, LLC\n"); + + seq_printf(m, "board\t\t: "); + + switch (katana_id) { + case KATANA_ID_3750: + seq_printf(m, "Katana 3750\n"); + break; + + case KATANA_ID_750I: + seq_printf(m, "Katana 750i\n"); + break; + + case KATANA_ID_752I: + seq_printf(m, "Katana 752i\n"); + break; + + default: + seq_printf(m, "Unknown\n"); + break; + } + + seq_printf(m, "product ID\t: 0x%x\n", + in_8(cpld_base + KATANA_CPLD_PRODUCT_ID)); + seq_printf(m, "hardware rev\t: 0x%x\n", + in_8(cpld_base+KATANA_CPLD_HARDWARE_VER)); + seq_printf(m, "PLD rev\t\t: 0x%x\n", + in_8(cpld_base + KATANA_CPLD_PLD_VER)); + seq_printf(m, "PLB freq\t: %ldMhz\n", + (long)katana_bus_frequency / 1000000); + seq_printf(m, "PCI\t\t: %sMonarch\n", katana_is_monarch()? "" : "Non-"); + + return 0; +} + +static void __init +katana_calibrate_decr(void) +{ + u32 freq; + + freq = katana_bus_frequency / 4; + + printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n", + (long)freq / 1000000, (long)freq % 1000000); + + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); +} + +unsigned long __init +katana_find_end_of_memory(void) +{ + return mv64x60_get_mem_size(CONFIG_MV64X60_NEW_BASE, + MV64x60_TYPE_MV64360); +} + +#if defined(CONFIG_I2C_MV64XXX) && defined(CONFIG_SENSORS_M41T00) +extern ulong m41t00_get_rtc_time(void); +extern int m41t00_set_rtc_time(ulong); + +static int __init +katana_rtc_hookup(void) +{ + struct timespec tv; + + ppc_md.get_rtc_time = m41t00_get_rtc_time; + ppc_md.set_rtc_time = m41t00_set_rtc_time; + + tv.tv_nsec = 0; + tv.tv_sec = (ppc_md.get_rtc_time)(); + do_settimeofday(&tv); + + return 0; +} +late_initcall(katana_rtc_hookup); +#endif + +static inline void +katana_set_bat(void) +{ + mb(); + mtspr(SPRN_DBAT2U, 0xf0001ffe); + mtspr(SPRN_DBAT2L, 0xf000002a); + mb(); +} + +#if defined(CONFIG_SERIAL_TEXT_DEBUG) && defined(CONFIG_SERIAL_MPSC_CONSOLE) +static void __init +katana_map_io(void) +{ + io_block_mapping(0xf8100000, 0xf8100000, 0x00020000, _PAGE_IO); +} +#endif + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + parse_bootinfo(find_bootinfo()); + + /* ASSUMPTION: If both r3 (bd_t pointer) and r6 (cmdline pointer) + * are non-zero, then we should use the board info from the bd_t + * structure and the cmdline pointed to by r6 instead of the + * information from birecs, if any. Otherwise, use the information + * from birecs as discovered by the preceeding call to + * parse_bootinfo(). This rule should work with both PPCBoot, which + * uses a bd_t board info structure, and the kernel boot wrapper, + * which uses birecs. + */ + if (r3 && r6) { + /* copy board info structure */ + memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) ); + /* copy command line */ + *(char *)(r7+KERNELBASE) = 0; + strcpy(cmd_line, (char *)(r6+KERNELBASE)); + } + + isa_mem_base = 0; + + ppc_md.setup_arch = katana_setup_arch; + ppc_md.show_cpuinfo = katana_show_cpuinfo; + ppc_md.init_IRQ = mv64360_init_irq; + ppc_md.get_irq = mv64360_get_irq; + ppc_md.restart = katana_restart; + ppc_md.power_off = katana_power_off; + ppc_md.halt = katana_halt; + ppc_md.find_end_of_memory = katana_find_end_of_memory; + ppc_md.calibrate_decr = katana_calibrate_decr; + +#if defined(CONFIG_SERIAL_TEXT_DEBUG) && defined(CONFIG_SERIAL_MPSC_CONSOLE) + ppc_md.setup_io_mappings = katana_map_io; + ppc_md.progress = mv64x60_mpsc_progress; + mv64x60_progress_init(CONFIG_MV64X60_NEW_BASE); +#endif + +#if defined(CONFIG_SERIAL_MPSC) || defined(CONFIG_MV643XX_ETH) + platform_notify = katana_platform_notify; +#endif + + katana_set_bat(); /* Need for katana_find_end_of_memory and progress */ +} diff --git a/arch/ppc/platforms/katana.h b/arch/ppc/platforms/katana.h new file mode 100644 index 00000000000..b82ed81950f --- /dev/null +++ b/arch/ppc/platforms/katana.h @@ -0,0 +1,255 @@ +/* + * arch/ppc/platforms/katana.h + * + * Definitions for Artesyn Katana750i/3750 board. + * + * Author: Tim Montgomery <timm@artesyncp.com> + * Maintained by: Mark A. Greer <mgreer@mvista.com> + * + * Based on code done by Rabeeh Khoury - rabeeh@galileo.co.il + * Based on code done by Mark A. Greer <mgreer@mvista.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/* + * The MV64360 has 2 PCI buses each with 1 window from the CPU bus to + * PCI I/O space and 4 windows from the CPU bus to PCI MEM space. + * We'll only use one PCI MEM window on each PCI bus. + * + * This is the CPU physical memory map (windows must be at least 64 KB and start + * on a boundary that is a multiple of the window size): + * + * 0xff800000-0xffffffff - Boot window + * 0xf8400000-0xf843ffff - Internal SRAM + * 0xf8200000-0xf83fffff - CPLD + * 0xf8100000-0xf810ffff - MV64360 Registers (CONFIG_MV64X60_NEW_BASE) + * 0xf8000000-0xf80fffff - Socketed FLASH + * 0xe0000000-0xefffffff - Soldered FLASH + * 0xc0000000-0xc3ffffff - PCI I/O (second hose) + * 0x80000000-0xbfffffff - PCI MEM (second hose) + */ + +#ifndef __PPC_PLATFORMS_KATANA_H +#define __PPC_PLATFORMS_KATANA_H + +/* CPU Physical Memory Map setup. */ +#define KATANA_BOOT_WINDOW_BASE 0xff800000 +#define KATANA_BOOT_WINDOW_SIZE 0x00800000 /* 8 MB */ +#define KATANA_INTERNAL_SRAM_BASE 0xf8400000 +#define KATANA_CPLD_BASE 0xf8200000 +#define KATANA_CPLD_SIZE 0x00200000 /* 2 MB */ +#define KATANA_SOCKET_BASE 0xf8000000 +#define KATANA_SOCKETED_FLASH_SIZE 0x00100000 /* 1 MB */ +#define KATANA_SOLDERED_FLASH_BASE 0xe0000000 +#define KATANA_SOLDERED_FLASH_SIZE 0x10000000 /* 256 MB */ + +#define KATANA_PCI1_MEM_START_PROC_ADDR 0x80000000 +#define KATANA_PCI1_MEM_START_PCI_HI_ADDR 0x00000000 +#define KATANA_PCI1_MEM_START_PCI_LO_ADDR 0x80000000 +#define KATANA_PCI1_MEM_SIZE 0x40000000 /* 1 GB */ +#define KATANA_PCI1_IO_START_PROC_ADDR 0xc0000000 +#define KATANA_PCI1_IO_START_PCI_ADDR 0x00000000 +#define KATANA_PCI1_IO_SIZE 0x04000000 /* 64 MB */ + +/* Board-specific IRQ info */ +#define KATANA_PCI_INTA_IRQ_3750 64+8 +#define KATANA_PCI_INTB_IRQ_3750 64+9 +#define KATANA_PCI_INTC_IRQ_3750 64+10 + +#define KATANA_PCI_INTA_IRQ_750i 64+8 +#define KATANA_PCI_INTB_IRQ_750i 64+9 +#define KATANA_PCI_INTC_IRQ_750i 64+10 +#define KATANA_PCI_INTD_IRQ_750i 64+14 + +#define KATANA_CPLD_RST_EVENT 0x00000000 +#define KATANA_CPLD_RST_CMD 0x00001000 +#define KATANA_CPLD_PCI_ERR_INT_EN 0x00002000 +#define KATANA_CPLD_PCI_ERR_INT_PEND 0x00003000 +#define KATANA_CPLD_PRODUCT_ID 0x00004000 +#define KATANA_CPLD_EREADY 0x00005000 + +#define KATANA_CPLD_HARDWARE_VER 0x00007000 +#define KATANA_CPLD_PLD_VER 0x00008000 +#define KATANA_CPLD_BD_CFG_0 0x00009000 +#define KATANA_CPLD_BD_CFG_1 0x0000a000 +#define KATANA_CPLD_BD_CFG_3 0x0000c000 +#define KATANA_CPLD_LED 0x0000d000 +#define KATANA_CPLD_RESET_OUT 0x0000e000 + +#define KATANA_CPLD_RST_EVENT_INITACT 0x80 +#define KATANA_CPLD_RST_EVENT_SW 0x40 +#define KATANA_CPLD_RST_EVENT_WD 0x20 +#define KATANA_CPLD_RST_EVENT_COPS 0x10 +#define KATANA_CPLD_RST_EVENT_COPH 0x08 +#define KATANA_CPLD_RST_EVENT_CPCI 0x02 +#define KATANA_CPLD_RST_EVENT_FP 0x01 + +#define KATANA_CPLD_RST_CMD_SCL 0x80 +#define KATANA_CPLD_RST_CMD_SDA 0x40 +#define KATANA_CPLD_RST_CMD_I2C 0x10 +#define KATANA_CPLD_RST_CMD_FR 0x08 +#define KATANA_CPLD_RST_CMD_SR 0x04 +#define KATANA_CPLD_RST_CMD_HR 0x01 + +#define KATANA_CPLD_BD_CFG_0_SYSCLK_MASK 0xc0 +#define KATANA_CPLD_BD_CFG_0_SYSCLK_200 0x00 +#define KATANA_CPLD_BD_CFG_0_SYSCLK_166 0x80 +#define KATANA_CPLD_BD_CFG_0_SYSCLK_133 0xc0 +#define KATANA_CPLD_BD_CFG_0_SYSCLK_100 0x40 + +#define KATANA_CPLD_BD_CFG_1_FL_BANK_MASK 0x03 +#define KATANA_CPLD_BD_CFG_1_FL_BANK_16MB 0x00 +#define KATANA_CPLD_BD_CFG_1_FL_BANK_32MB 0x01 +#define KATANA_CPLD_BD_CFG_1_FL_BANK_64MB 0x02 +#define KATANA_CPLD_BD_CFG_1_FL_BANK_128MB 0x03 + +#define KATANA_CPLD_BD_CFG_1_FL_NUM_BANKS_MASK 0x04 +#define KATANA_CPLD_BD_CFG_1_FL_NUM_BANKS_ONE 0x00 +#define KATANA_CPLD_BD_CFG_1_FL_NUM_BANKS_TWO 0x04 + +#define KATANA_CPLD_BD_CFG_3_MONARCH 0x04 + +#define KATANA_CPLD_RESET_OUT_PORTSEL 0x80 +#define KATANA_CPLD_RESET_OUT_WD 0x20 +#define KATANA_CPLD_RESET_OUT_COPH 0x08 +#define KATANA_CPLD_RESET_OUT_PCI_RST_PCI 0x02 +#define KATANA_CPLD_RESET_OUT_PCI_RST_FP 0x01 + +#define KATANA_MBOX_RESET_REQUEST 0xC83A +#define KATANA_MBOX_RESET_ACK 0xE430 +#define KATANA_MBOX_RESET_DONE 0x32E5 + +#define HSL_PLD_BASE 0x00010000 +#define HSL_PLD_J4SGA_REG_OFF 0 +#define HSL_PLD_J4GA_REG_OFF 1 +#define HSL_PLD_J2GA_REG_OFF 2 +#define HSL_PLD_HOT_SWAP_OFF 6 +#define HSL_PLD_HOT_SWAP_LED_BIT 0x1 +#define GA_MASK 0x1f +#define HSL_PLD_SIZE 0x1000 +#define K3750_GPP_GEO_ADDR_PINS 0xf8000000 +#define K3750_GPP_GEO_ADDR_SHIFT 27 + +#define K3750_GPP_EVENT_PROC_0 (1 << 21) +#define K3750_GPP_EVENT_PROC_1_2 (1 << 2) + +#define PCI_VENDOR_ID_ARTESYN 0x1223 +#define PCI_DEVICE_ID_KATANA_3750_PROC0 0x0041 +#define PCI_DEVICE_ID_KATANA_3750_PROC1 0x0042 +#define PCI_DEVICE_ID_KATANA_3750_PROC2 0x0043 + +#define COPROC_MEM_FUNCTION 0 +#define COPROC_MEM_BAR 0 +#define COPROC_REGS_FUNCTION 0 +#define COPROC_REGS_BAR 4 +#define COPROC_FLASH_FUNCTION 2 +#define COPROC_FLASH_BAR 4 + +#define KATANA_IPMB_LOCAL_I2C_ADDR 0x08 + +#define KATANA_DEFAULT_BAUD 9600 +#define KATANA_MPSC_CLK_SRC 8 /* TCLK */ + +#define KATANA_MTD_MONITOR_SIZE (1 << 20) /* 1 MB */ + +#define KATANA_ETH0_PHY_ADDR 12 +#define KATANA_ETH1_PHY_ADDR 11 +#define KATANA_ETH2_PHY_ADDR 4 + +#define KATANA_PRODUCT_ID_3750 0x01 +#define KATANA_PRODUCT_ID_750i 0x02 +#define KATANA_PRODUCT_ID_752i 0x04 + +#define KATANA_ETH_TX_QUEUE_SIZE 800 +#define KATANA_ETH_RX_QUEUE_SIZE 400 + +#define KATANA_ETH_PORT_CONFIG_VALUE \ + ETH_UNICAST_NORMAL_MODE | \ + ETH_DEFAULT_RX_QUEUE_0 | \ + ETH_DEFAULT_RX_ARP_QUEUE_0 | \ + ETH_RECEIVE_BC_IF_NOT_IP_OR_ARP | \ + ETH_RECEIVE_BC_IF_IP | \ + ETH_RECEIVE_BC_IF_ARP | \ + ETH_CAPTURE_TCP_FRAMES_DIS | \ + ETH_CAPTURE_UDP_FRAMES_DIS | \ + ETH_DEFAULT_RX_TCP_QUEUE_0 | \ + ETH_DEFAULT_RX_UDP_QUEUE_0 | \ + ETH_DEFAULT_RX_BPDU_QUEUE_0 + +#define KATANA_ETH_PORT_CONFIG_EXTEND_VALUE \ + ETH_SPAN_BPDU_PACKETS_AS_NORMAL | \ + ETH_PARTITION_DISABLE + +#define GT_ETH_IPG_INT_RX(value) \ + ((value & 0x3fff) << 8) + +#define KATANA_ETH_PORT_SDMA_CONFIG_VALUE \ + ETH_RX_BURST_SIZE_4_64BIT | \ + GT_ETH_IPG_INT_RX(0) | \ + ETH_TX_BURST_SIZE_4_64BIT + +#define KATANA_ETH_PORT_SERIAL_CONTROL_VALUE \ + ETH_FORCE_LINK_PASS | \ + ETH_ENABLE_AUTO_NEG_FOR_DUPLX | \ + ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL | \ + ETH_ADV_SYMMETRIC_FLOW_CTRL | \ + ETH_FORCE_FC_MODE_NO_PAUSE_DIS_TX | \ + ETH_FORCE_BP_MODE_NO_JAM | \ + BIT9 | \ + ETH_DO_NOT_FORCE_LINK_FAIL | \ + ETH_RETRANSMIT_16_ATTEMPTS | \ + ETH_ENABLE_AUTO_NEG_SPEED_GMII | \ + ETH_DTE_ADV_0 | \ + ETH_DISABLE_AUTO_NEG_BYPASS | \ + ETH_AUTO_NEG_NO_CHANGE | \ + ETH_MAX_RX_PACKET_9700BYTE | \ + ETH_CLR_EXT_LOOPBACK | \ + ETH_SET_FULL_DUPLEX_MODE | \ + ETH_ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX + +#ifndef __ASSEMBLY__ + +typedef enum { + KATANA_ID_3750, + KATANA_ID_750I, + KATANA_ID_752I, + KATANA_ID_MAX +} katana_id_t; + +#endif + +static inline u32 +katana_bus_freq(void __iomem *cpld_base) +{ + u8 bd_cfg_0; + + bd_cfg_0 = in_8(cpld_base + KATANA_CPLD_BD_CFG_0); + + switch (bd_cfg_0 & KATANA_CPLD_BD_CFG_0_SYSCLK_MASK) { + case KATANA_CPLD_BD_CFG_0_SYSCLK_200: + return 200000000; + break; + + case KATANA_CPLD_BD_CFG_0_SYSCLK_166: + return 166666666; + break; + + case KATANA_CPLD_BD_CFG_0_SYSCLK_133: + return 133333333; + break; + + case KATANA_CPLD_BD_CFG_0_SYSCLK_100: + return 100000000; + break; + + default: + return 133333333; + break; + } +} + +#endif /* __PPC_PLATFORMS_KATANA_H */ diff --git a/arch/ppc/platforms/lantec.h b/arch/ppc/platforms/lantec.h new file mode 100644 index 00000000000..8c87642c510 --- /dev/null +++ b/arch/ppc/platforms/lantec.h @@ -0,0 +1,21 @@ +/* + * LANTEC board specific definitions + * + * Copyright (c) 2001 Wolfgang Denk (wd@denx.de) + */ + +#ifndef __MACH_LANTEC_H +#define __MACH_LANTEC_H + +#include <linux/config.h> + +#include <asm/ppcboot.h> + +#define IMAP_ADDR 0xFFF00000 /* physical base address of IMMR area */ +#define IMAP_SIZE (64 * 1024) /* mapped size of IMMR area */ + +/* We don't use the 8259. +*/ +#define NR_8259_INTS 0 + +#endif /* __MACH_LANTEC_H */ diff --git a/arch/ppc/platforms/lite5200.c b/arch/ppc/platforms/lite5200.c new file mode 100644 index 00000000000..b604cf8b3ca --- /dev/null +++ b/arch/ppc/platforms/lite5200.c @@ -0,0 +1,236 @@ +/* + * arch/ppc/platforms/lite5200.c + * + * Platform support file for the Freescale LITE5200 based on MPC52xx. + * A maximum of this file should be moved to syslib/mpc52xx_????? + * so that new platform based on MPC52xx need a minimal platform file + * ( avoid code duplication ) + * + * + * Maintainer : Sylvain Munaut <tnt@246tNt.com> + * + * Based on the 2.4 code written by Kent Borg, + * Dale Farnsworth <dale.farnsworth@mvista.com> and + * Wolfgang Denk <wd@denx.de> + * + * Copyright 2004-2005 Sylvain Munaut <tnt@246tNt.com> + * Copyright 2003 Motorola Inc. + * Copyright 2003 MontaVista Software Inc. + * Copyright 2003 DENX Software Engineering (wd@denx.de) + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/config.h> +#include <linux/initrd.h> +#include <linux/seq_file.h> +#include <linux/kdev_t.h> +#include <linux/root_dev.h> +#include <linux/console.h> +#include <linux/module.h> + +#include <asm/bootinfo.h> +#include <asm/io.h> +#include <asm/mpc52xx.h> +#include <asm/ppc_sys.h> + +#include <syslib/mpc52xx_pci.h> + + +extern int powersave_nap; + +/* Board data given by U-Boot */ +bd_t __res; +EXPORT_SYMBOL(__res); /* For modules */ + + +/* ======================================================================== */ +/* Platform specific code */ +/* ======================================================================== */ + +/* Supported PSC function in "preference" order */ +struct mpc52xx_psc_func mpc52xx_psc_functions[] = { + { .id = 0, + .func = "uart", + }, + { .id = -1, /* End entry */ + .func = NULL, + } + }; + + +static int +lite5200_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "machine\t\t: Freescale LITE5200\n"); + return 0; +} + +#ifdef CONFIG_PCI +static int +lite5200_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + return (pin == 1) && (idsel==24) ? MPC52xx_IRQ0 : -1; +} +#endif + +static void __init +lite5200_setup_cpu(void) +{ + struct mpc52xx_cdm __iomem *cdm; + struct mpc52xx_gpio __iomem *gpio; + struct mpc52xx_intr __iomem *intr; + struct mpc52xx_xlb __iomem *xlb; + + u32 port_config; + u32 intr_ctrl; + + /* Map zones */ + cdm = ioremap(MPC52xx_PA(MPC52xx_CDM_OFFSET), MPC52xx_CDM_SIZE); + gpio = ioremap(MPC52xx_PA(MPC52xx_GPIO_OFFSET), MPC52xx_GPIO_SIZE); + xlb = ioremap(MPC52xx_PA(MPC52xx_XLB_OFFSET), MPC52xx_XLB_SIZE); + intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), MPC52xx_INTR_SIZE); + + if (!cdm || !gpio || !xlb || !intr) { + printk("lite5200.c: Error while mapping CDM/GPIO/XLB/INTR during" + "lite5200_setup_cpu\n"); + goto unmap_regs; + } + + /* Use internal 48 Mhz */ + out_8(&cdm->ext_48mhz_en, 0x00); + out_8(&cdm->fd_enable, 0x01); + if (in_be32(&cdm->rstcfg) & 0x40) /* Assumes 33Mhz clock */ + out_be16(&cdm->fd_counters, 0x0001); + else + out_be16(&cdm->fd_counters, 0x5555); + + /* Get port mux config */ + port_config = in_be32(&gpio->port_config); + + /* 48Mhz internal, pin is GPIO */ + port_config &= ~0x00800000; + + /* USB port */ + port_config &= ~0x00007000; /* Differential mode - USB1 only */ + port_config |= 0x00001000; + + /* Commit port config */ + out_be32(&gpio->port_config, port_config); + + /* Configure the XLB Arbiter */ + out_be32(&xlb->master_pri_enable, 0xff); + out_be32(&xlb->master_priority, 0x11111111); + + /* Enable ram snooping for 1GB window */ + out_be32(&xlb->config, in_be32(&xlb->config) | MPC52xx_XLB_CFG_SNOOP); + out_be32(&xlb->snoop_window, MPC52xx_PCI_TARGET_MEM | 0x1d); + + /* IRQ[0-3] setup : IRQ0 - Level Active Low */ + /* IRQ[1-3] - Level Active High */ + intr_ctrl = in_be32(&intr->ctrl); + intr_ctrl &= ~0x00ff0000; + intr_ctrl |= 0x00c00000; + out_be32(&intr->ctrl, intr_ctrl); + + /* Unmap reg zone */ +unmap_regs: + if (cdm) iounmap(cdm); + if (gpio) iounmap(gpio); + if (xlb) iounmap(xlb); + if (intr) iounmap(intr); +} + +static void __init +lite5200_setup_arch(void) +{ + /* CPU & Port mux setup */ + lite5200_setup_cpu(); + +#ifdef CONFIG_PCI + /* PCI Bridge setup */ + mpc52xx_find_bridges(); +#endif +} + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + /* Generic MPC52xx platform initialization */ + /* TODO Create one and move a max of stuff in it. + Put this init in the syslib */ + + struct bi_record *bootinfo = find_bootinfo(); + + if (bootinfo) + parse_bootinfo(bootinfo); + else { + /* Load the bd_t board info structure */ + if (r3) + memcpy((void*)&__res,(void*)(r3+KERNELBASE), + sizeof(bd_t)); + +#ifdef CONFIG_BLK_DEV_INITRD + /* Load the initrd */ + if (r4) { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif + + /* Load the command line */ + if (r6) { + *(char *)(r7+KERNELBASE) = 0; + strcpy(cmd_line, (char *)(r6+KERNELBASE)); + } + } + + /* PPC Sys identification */ + identify_ppc_sys_by_id(mfspr(SPRN_SVR)); + + /* BAT setup */ + mpc52xx_set_bat(); + + /* No ISA bus by default */ + isa_io_base = 0; + isa_mem_base = 0; + + /* Powersave */ + /* This is provided as an example on how to do it. But you + need to be aware that NAP disable bus snoop and that may + be required for some devices to work properly, like USB ... */ + /* powersave_nap = 1; */ + + + /* Setup the ppc_md struct */ + ppc_md.setup_arch = lite5200_setup_arch; + ppc_md.show_cpuinfo = lite5200_show_cpuinfo; + ppc_md.show_percpuinfo = NULL; + ppc_md.init_IRQ = mpc52xx_init_irq; + ppc_md.get_irq = mpc52xx_get_irq; + +#ifdef CONFIG_PCI + ppc_md.pci_map_irq = lite5200_map_irq; +#endif + + ppc_md.find_end_of_memory = mpc52xx_find_end_of_memory; + ppc_md.setup_io_mappings = mpc52xx_map_io; + + ppc_md.restart = mpc52xx_restart; + ppc_md.power_off = mpc52xx_power_off; + ppc_md.halt = mpc52xx_halt; + + /* No time keeper on the LITE5200 */ + ppc_md.time_init = NULL; + ppc_md.get_rtc_time = NULL; + ppc_md.set_rtc_time = NULL; + + ppc_md.calibrate_decr = mpc52xx_calibrate_decr; +#ifdef CONFIG_SERIAL_TEXT_DEBUG + ppc_md.progress = mpc52xx_progress; +#endif +} + diff --git a/arch/ppc/platforms/lite5200.h b/arch/ppc/platforms/lite5200.h new file mode 100644 index 00000000000..c1de2aa4717 --- /dev/null +++ b/arch/ppc/platforms/lite5200.h @@ -0,0 +1,23 @@ +/* + * arch/ppc/platforms/lite5200.h + * + * Definitions for Freescale LITE5200 : MPC52xx Standard Development + * Platform board support + * + * Maintainer : Sylvain Munaut <tnt@246tNt.com> + * + * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef __PLATFORMS_LITE5200_H__ +#define __PLATFORMS_LITE5200_H__ + +/* Serial port used for low-level debug */ +#define MPC52xx_PF_CONSOLE_PORT 1 /* PSC1 */ + + +#endif /* __PLATFORMS_LITE5200_H__ */ diff --git a/arch/ppc/platforms/lopec.c b/arch/ppc/platforms/lopec.c new file mode 100644 index 00000000000..a5569525e0a --- /dev/null +++ b/arch/ppc/platforms/lopec.c @@ -0,0 +1,411 @@ +/* + * arch/ppc/platforms/lopec.c + * + * Setup routines for the Motorola LoPEC. + * + * Author: Dan Cox + * Maintainer: Tom Rini <trini@kernel.crashing.org> + * + * 2001-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. + */ + +#include <linux/config.h> +#include <linux/types.h> +#include <linux/delay.h> +#include <linux/pci_ids.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/ide.h> +#include <linux/seq_file.h> +#include <linux/initrd.h> +#include <linux/console.h> +#include <linux/root_dev.h> +#include <linux/pci.h> + +#include <asm/machdep.h> +#include <asm/pci-bridge.h> +#include <asm/io.h> +#include <asm/open_pic.h> +#include <asm/i8259.h> +#include <asm/todc.h> +#include <asm/bootinfo.h> +#include <asm/mpc10x.h> +#include <asm/hw_irq.h> +#include <asm/prep_nvram.h> +#include <asm/kgdb.h> + +/* + * Define all of the IRQ senses and polarities. Taken from the + * LoPEC Programmer's Reference Guide. + */ +static u_char lopec_openpic_initsenses[16] __initdata = { + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ 0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ 2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 3 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ 4 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ 5 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 6 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 7 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 8 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 9 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 10 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 11 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 12 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ 13 */ + (IRQ_SENSE_EDGE | IRQ_POLARITY_NEGATIVE), /* IRQ 14 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE) /* IRQ 15 */ +}; + +static inline int __init +lopec_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + int irq; + static char pci_irq_table[][4] = { + {16, 0, 0, 0}, /* ID 11 - Winbond */ + {22, 0, 0, 0}, /* ID 12 - SCSI */ + {0, 0, 0, 0}, /* ID 13 - nothing */ + {17, 0, 0, 0}, /* ID 14 - 82559 Ethernet */ + {27, 0, 0, 0}, /* ID 15 - USB */ + {23, 0, 0, 0}, /* ID 16 - PMC slot 1 */ + {24, 0, 0, 0}, /* ID 17 - PMC slot 2 */ + {25, 0, 0, 0}, /* ID 18 - PCI slot */ + {0, 0, 0, 0}, /* ID 19 - nothing */ + {0, 0, 0, 0}, /* ID 20 - nothing */ + {0, 0, 0, 0}, /* ID 21 - nothing */ + {0, 0, 0, 0}, /* ID 22 - nothing */ + {0, 0, 0, 0}, /* ID 23 - nothing */ + {0, 0, 0, 0}, /* ID 24 - PMC slot 1b */ + {0, 0, 0, 0}, /* ID 25 - nothing */ + {0, 0, 0, 0} /* ID 26 - PMC Slot 2b */ + }; + const long min_idsel = 11, max_idsel = 26, irqs_per_slot = 4; + + irq = PCI_IRQ_TABLE_LOOKUP; + if (!irq) + return 0; + + return irq; +} + +static void __init +lopec_setup_winbond_83553(struct pci_controller *hose) +{ + int devfn; + + devfn = PCI_DEVFN(11,0); + + /* IDE interrupt routing (primary 14, secondary 15) */ + early_write_config_byte(hose, 0, devfn, 0x43, 0xef); + /* PCI interrupt routing */ + early_write_config_word(hose, 0, devfn, 0x44, 0x0000); + + /* ISA-PCI address decoder */ + early_write_config_byte(hose, 0, devfn, 0x48, 0xf0); + + /* RTC, kb, not used in PPC */ + early_write_config_byte(hose, 0, devfn, 0x4d, 0x00); + early_write_config_byte(hose, 0, devfn, 0x4e, 0x04); + devfn = PCI_DEVFN(11, 1); + early_write_config_byte(hose, 0, devfn, 0x09, 0x8f); + early_write_config_dword(hose, 0, devfn, 0x40, 0x00ff0011); +} + +static void __init +lopec_find_bridges(void) +{ + struct pci_controller *hose; + + hose = pcibios_alloc_controller(); + if (!hose) + return; + + hose->first_busno = 0; + hose->last_busno = 0xff; + + if (mpc10x_bridge_init(hose, MPC10X_MEM_MAP_B, MPC10X_MEM_MAP_B, + MPC10X_MAPB_EUMB_BASE) == 0) { + + hose->mem_resources[0].end = 0xffffffff; + lopec_setup_winbond_83553(hose); + hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = lopec_map_irq; + } +} + +static int +lopec_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "machine\t\t: Motorola LoPEC\n"); + return 0; +} + +static u32 +lopec_irq_canonicalize(u32 irq) +{ + if (irq == 2) + return 9; + else + return irq; +} + +static void +lopec_restart(char *cmd) +{ +#define LOPEC_SYSSTAT1 0xffe00000 + /* force a hard reset, if possible */ + unsigned char reg = *((unsigned char *) LOPEC_SYSSTAT1); + reg |= 0x80; + *((unsigned char *) LOPEC_SYSSTAT1) = reg; + + local_irq_disable(); + while(1); +#undef LOPEC_SYSSTAT1 +} + +static void +lopec_halt(void) +{ + local_irq_disable(); + while(1); +} + +static void +lopec_power_off(void) +{ + lopec_halt(); +} + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +int lopec_ide_ports_known = 0; +static unsigned long lopec_ide_regbase[MAX_HWIFS]; +static unsigned long lopec_ide_ctl_regbase[MAX_HWIFS]; +static unsigned long lopec_idedma_regbase; + +static void +lopec_ide_probe(void) +{ + struct pci_dev *dev = pci_get_device(PCI_VENDOR_ID_WINBOND, + PCI_DEVICE_ID_WINBOND_82C105, + NULL); + lopec_ide_ports_known = 1; + + if (dev) { + lopec_ide_regbase[0] = dev->resource[0].start; + lopec_ide_regbase[1] = dev->resource[2].start; + lopec_ide_ctl_regbase[0] = dev->resource[1].start; + lopec_ide_ctl_regbase[1] = dev->resource[3].start; + lopec_idedma_regbase = dev->resource[4].start; + pci_dev_put(dev); + } +} + +static int +lopec_ide_default_irq(unsigned long base) +{ + if (lopec_ide_ports_known == 0) + lopec_ide_probe(); + + if (base == lopec_ide_regbase[0]) + return 14; + else if (base == lopec_ide_regbase[1]) + return 15; + else + return 0; +} + +static unsigned long +lopec_ide_default_io_base(int index) +{ + if (lopec_ide_ports_known == 0) + lopec_ide_probe(); + return lopec_ide_regbase[index]; +} + +static void __init +lopec_ide_init_hwif_ports(hw_regs_t *hw, unsigned long data, + unsigned long ctl, int *irq) +{ + unsigned long reg = data; + uint alt_status_base; + int i; + + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) + hw->io_ports[i] = reg++; + + if (data == lopec_ide_regbase[0]) { + alt_status_base = lopec_ide_ctl_regbase[0] + 2; + hw->irq = 14; + } else if (data == lopec_ide_regbase[1]) { + alt_status_base = lopec_ide_ctl_regbase[1] + 2; + hw->irq = 15; + } else { + alt_status_base = 0; + hw->irq = 0; + } + + if (ctl) + hw->io_ports[IDE_CONTROL_OFFSET] = ctl; + else + hw->io_ports[IDE_CONTROL_OFFSET] = alt_status_base; + + if (irq != NULL) + *irq = hw->irq; + +} +#endif /* BLK_DEV_IDE */ + +static void __init +lopec_init_IRQ(void) +{ + int i; + + /* + * Provide the open_pic code with the correct table of interrupts. + */ + OpenPIC_InitSenses = lopec_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof(lopec_openpic_initsenses); + + mpc10x_set_openpic(); + + /* We have a cascade on OpenPIC IRQ 0, Linux IRQ 16 */ + openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade", + &i8259_irq); + + /* Map i8259 interrupts */ + for(i = 0; i < NUM_8259_INTERRUPTS; i++) + irq_desc[i].handler = &i8259_pic; + + /* + * The EPIC allows for a read in the range of 0xFEF00000 -> + * 0xFEFFFFFF to generate a PCI interrupt-acknowledge transaction. + */ + i8259_init(0xfef00000); +} + +static int __init +lopec_request_io(void) +{ + outb(0x00, 0x4d0); + outb(0xc0, 0x4d1); + + request_region(0x00, 0x20, "dma1"); + request_region(0x20, 0x20, "pic1"); + request_region(0x40, 0x20, "timer"); + request_region(0x80, 0x10, "dma page reg"); + request_region(0xa0, 0x20, "pic2"); + request_region(0xc0, 0x20, "dma2"); + + return 0; +} + +device_initcall(lopec_request_io); + +static void __init +lopec_map_io(void) +{ + io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO); + io_block_mapping(0xb0000000, 0xb0000000, 0x10000000, _PAGE_IO); +} + +/* + * Set BAT 3 to map 0xf8000000 to end of physical memory space 1-to-1. + */ +static __inline__ void +lopec_set_bat(void) +{ + mb(); + mtspr(SPRN_DBAT1U, 0xf8000ffe); + mtspr(SPRN_DBAT1L, 0xf800002a); + mb(); +} + +TODC_ALLOC(); + +static void __init +lopec_setup_arch(void) +{ + + TODC_INIT(TODC_TYPE_MK48T37, 0, 0, + ioremap(0xffe80000, 0x8000), 8); + + loops_per_jiffy = 100000000/HZ; + + lopec_find_bridges(); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#elif defined(CONFIG_ROOT_NFS) + ROOT_DEV = Root_NFS; +#elif defined(CONFIG_BLK_DEV_IDEDISK) + ROOT_DEV = Root_HDA1; +#else + ROOT_DEV = Root_SDA1; +#endif + +#ifdef CONFIG_PPCBUG_NVRAM + /* Read in NVRAM data */ + init_prep_nvram(); + + /* if no bootargs, look in NVRAM */ + if ( cmd_line[0] == '\0' ) { + char *bootargs; + bootargs = prep_nvram_get_var("bootargs"); + if (bootargs != NULL) { + strcpy(cmd_line, bootargs); + /* again.. */ + strcpy(saved_command_line, cmd_line); + } + } +#endif +} + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + parse_bootinfo(find_bootinfo()); + lopec_set_bat(); + + isa_io_base = MPC10X_MAPB_ISA_IO_BASE; + isa_mem_base = MPC10X_MAPB_ISA_MEM_BASE; + pci_dram_offset = MPC10X_MAPB_DRAM_OFFSET; + ISA_DMA_THRESHOLD = 0x00ffffff; + DMA_MODE_READ = 0x44; + DMA_MODE_WRITE = 0x48; + + ppc_md.setup_arch = lopec_setup_arch; + ppc_md.show_cpuinfo = lopec_show_cpuinfo; + ppc_md.irq_canonicalize = lopec_irq_canonicalize; + ppc_md.init_IRQ = lopec_init_IRQ; + ppc_md.get_irq = openpic_get_irq; + + ppc_md.restart = lopec_restart; + ppc_md.power_off = lopec_power_off; + ppc_md.halt = lopec_halt; + + ppc_md.setup_io_mappings = lopec_map_io; + + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.calibrate_decr = todc_calibrate_decr; + + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) + ppc_ide_md.default_irq = lopec_ide_default_irq; + ppc_ide_md.default_io_base = lopec_ide_default_io_base; + ppc_ide_md.ide_init_hwif = lopec_ide_init_hwif_ports; +#endif +#ifdef CONFIG_SERIAL_TEXT_DEBUG + ppc_md.progress = gen550_progress; +#endif +} diff --git a/arch/ppc/platforms/lopec.h b/arch/ppc/platforms/lopec.h new file mode 100644 index 00000000000..5490edb2d26 --- /dev/null +++ b/arch/ppc/platforms/lopec.h @@ -0,0 +1,39 @@ +/* + * include/asm-ppc/lopec_serial.h + * + * Definitions for Motorola LoPEC board. + * + * Author: Dan Cox + * danc@mvista.com (or, alternately, source@mvista.com) + * + * 2001 (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. + */ + +#ifndef __H_LOPEC_SERIAL +#define __H_LOPEC_SERIAL + +#define RS_TABLE_SIZE 3 + +#define BASE_BAUD (1843200 / 16) + +#ifdef CONFIG_SERIAL_DETECT_IRQ +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ) +#else +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST) +#endif + +#define SERIAL_PORT_DFNS \ + { 0, BASE_BAUD, 0xffe10000, 29, STD_COM_FLAGS, \ + iomem_base: (u8 *) 0xffe10000, \ + io_type: SERIAL_IO_MEM }, \ + { 0, BASE_BAUD, 0xffe11000, 20, STD_COM_FLAGS, \ + iomem_base: (u8 *) 0xffe11000, \ + io_type: SERIAL_IO_MEM }, \ + { 0, BASE_BAUD, 0xffe12000, 21, STD_COM_FLAGS, \ + iomem_base: (u8 *) 0xffe12000, \ + io_type: SERIAL_IO_MEM } + +#endif diff --git a/arch/ppc/platforms/lwmon.h b/arch/ppc/platforms/lwmon.h new file mode 100644 index 00000000000..995bf5112df --- /dev/null +++ b/arch/ppc/platforms/lwmon.h @@ -0,0 +1,60 @@ +/* + * Liebherr LWMON board specific definitions + * + * Copyright (c) 2001 Wolfgang Denk (wd@denx.de) + */ + +#ifndef __MACH_LWMON_H +#define __MACH_LWMON_H + +#include <linux/config.h> + +#include <asm/ppcboot.h> + +#define IMAP_ADDR 0xFFF00000 /* physical base address of IMMR area */ +#define IMAP_SIZE (64 * 1024) /* mapped size of IMMR area */ + +/*----------------------------------------------------------------------- + * PCMCIA stuff + *----------------------------------------------------------------------- + * + */ +#define PCMCIA_MEM_SIZE ( 64 << 20 ) + +#define MAX_HWIFS 1 /* overwrite default in include/asm-ppc/ide.h */ + +/* + * Definitions for IDE0 Interface + */ +#define IDE0_BASE_OFFSET 0 +#define IDE0_DATA_REG_OFFSET (PCMCIA_MEM_SIZE + 0x320) +#define IDE0_ERROR_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 1) +#define IDE0_NSECTOR_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 2) +#define IDE0_SECTOR_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 3) +#define IDE0_LCYL_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 4) +#define IDE0_HCYL_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 5) +#define IDE0_SELECT_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 6) +#define IDE0_STATUS_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 7) +#define IDE0_CONTROL_REG_OFFSET 0x0106 +#define IDE0_IRQ_REG_OFFSET 0x000A /* not used */ + +#define IDE0_INTERRUPT 13 + +/* + * Definitions for I2C devices + */ +#define I2C_ADDR_AUDIO 0x28 /* Audio volume control */ +#define I2C_ADDR_SYSMON 0x2E /* LM87 System Monitor */ +#define I2C_ADDR_RTC 0x51 /* PCF8563 RTC */ +#define I2C_ADDR_POWER_A 0x52 /* PCMCIA/USB power switch, channel A */ +#define I2C_ADDR_POWER_B 0x53 /* PCMCIA/USB power switch, channel B */ +#define I2C_ADDR_KEYBD 0x56 /* PIC LWE keyboard */ +#define I2C_ADDR_PICIO 0x57 /* PIC IO Expander */ +#define I2C_ADDR_EEPROM 0x58 /* EEPROM AT24C164 */ + + +/* We don't use the 8259. +*/ +#define NR_8259_INTS 0 + +#endif /* __MACH_LWMON_H */ diff --git a/arch/ppc/platforms/mbx.h b/arch/ppc/platforms/mbx.h new file mode 100644 index 00000000000..fe81ca4ea0a --- /dev/null +++ b/arch/ppc/platforms/mbx.h @@ -0,0 +1,117 @@ +/* + * A collection of structures, addresses, and values associated with + * the Motorola MBX boards. This was originally created for the + * MBX860, and probably needs revisions for other boards (like the 821). + * When this file gets out of control, we can split it up into more + * meaningful pieces. + * + * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) + */ +#ifdef __KERNEL__ +#ifndef __MACH_MBX_DEFS +#define __MACH_MBX_DEFS + +#ifndef __ASSEMBLY__ +/* A Board Information structure that is given to a program when + * EPPC-Bug starts it up. + */ +typedef struct bd_info { + unsigned int bi_tag; /* Should be 0x42444944 "BDID" */ + unsigned int bi_size; /* Size of this structure */ + unsigned int bi_revision; /* revision of this structure */ + unsigned int bi_bdate; /* EPPCbug date, i.e. 0x11061997 */ + unsigned int bi_memstart; /* Memory start address */ + unsigned int bi_memsize; /* Memory (end) size in bytes */ + unsigned int bi_intfreq; /* Internal Freq, in Hz */ + unsigned int bi_busfreq; /* Bus Freq, in Hz */ + unsigned int bi_clun; /* Boot device controller */ + unsigned int bi_dlun; /* Boot device logical dev */ + + /* These fields are not part of the board information structure + * provided by the boot rom. They are filled in by embed_config.c + * so we have the information consistent with other platforms. + */ + unsigned char bi_enetaddr[6]; + unsigned int bi_baudrate; +} bd_t; + +/* Memory map for the MBX as configured by EPPC-Bug. We could reprogram + * The SIU and PCI bridge, and try to use larger MMU pages, but the + * performance gain is not measureable and it certainly complicates the + * generic MMU model. + * + * In a effort to minimize memory usage for embedded applications, any + * PCI driver or ISA driver must request or map the region required by + * the device. For convenience (and since we can map up to 4 Mbytes with + * a single page table page), the MMU initialization will map the + * NVRAM, Status/Control registers, CPM Dual Port RAM, and the PCI + * Bridge CSRs 1:1 into the kernel address space. + */ +#define PCI_ISA_IO_ADDR ((unsigned)0x80000000) +#define PCI_ISA_IO_SIZE ((uint)(512 * 1024 * 1024)) +#define PCI_IDE_ADDR ((unsigned)0x81000000) +#define PCI_ISA_MEM_ADDR ((unsigned)0xc0000000) +#define PCI_ISA_MEM_SIZE ((uint)(512 * 1024 * 1024)) +#define PCMCIA_MEM_ADDR ((uint)0xe0000000) +#define PCMCIA_MEM_SIZE ((uint)(64 * 1024 * 1024)) +#define PCMCIA_DMA_ADDR ((uint)0xe4000000) +#define PCMCIA_DMA_SIZE ((uint)(64 * 1024 * 1024)) +#define PCMCIA_ATTRB_ADDR ((uint)0xe8000000) +#define PCMCIA_ATTRB_SIZE ((uint)(64 * 1024 * 1024)) +#define PCMCIA_IO_ADDR ((uint)0xec000000) +#define PCMCIA_IO_SIZE ((uint)(64 * 1024 * 1024)) +#define NVRAM_ADDR ((uint)0xfa000000) +#define NVRAM_SIZE ((uint)(1 * 1024 * 1024)) +#define MBX_CSR_ADDR ((uint)0xfa100000) +#define MBX_CSR_SIZE ((uint)(1 * 1024 * 1024)) +#define IMAP_ADDR ((uint)0xfa200000) +#define IMAP_SIZE ((uint)(64 * 1024)) +#define PCI_CSR_ADDR ((uint)0xfa210000) +#define PCI_CSR_SIZE ((uint)(64 * 1024)) + +/* Map additional physical space into well known virtual addresses. Due + * to virtual address mapping, these physical addresses are not accessible + * in a 1:1 virtual to physical mapping. + */ +#define ISA_IO_VIRT_ADDR ((uint)0xfa220000) +#define ISA_IO_VIRT_SIZE ((uint)64 * 1024) + +/* Interrupt assignments. + * These are defined (and fixed) by the MBX hardware implementation. + */ +#define POWER_FAIL_INT SIU_IRQ0 /* Power fail */ +#define TEMP_HILO_INT SIU_IRQ1 /* Temperature sensor */ +#define QSPAN_INT SIU_IRQ2 /* PCI Bridge (DMA CTLR?) */ +#define ISA_BRIDGE_INT SIU_IRQ3 /* All those PC things */ +#define COMM_L_INT SIU_IRQ6 /* MBX Comm expansion connector pin */ +#define STOP_ABRT_INT SIU_IRQ7 /* Stop/Abort header pin */ + +/* CPM Ethernet through SCCx. + * + * Bits in parallel I/O port registers that have to be set/cleared + * to configure the pins for SCC1 use. The TCLK and RCLK seem unique + * to the MBX860 board. Any two of the four available clocks could be + * used, and the MPC860 cookbook manual has an example using different + * clock pins. + */ +#define PA_ENET_RXD ((ushort)0x0001) +#define PA_ENET_TXD ((ushort)0x0002) +#define PA_ENET_TCLK ((ushort)0x0200) +#define PA_ENET_RCLK ((ushort)0x0800) +#define PC_ENET_TENA ((ushort)0x0001) +#define PC_ENET_CLSN ((ushort)0x0010) +#define PC_ENET_RENA ((ushort)0x0020) + +/* Control bits in the SICR to route TCLK (CLK2) and RCLK (CLK4) to + * SCC1. Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero. + */ +#define SICR_ENET_MASK ((uint)0x000000ff) +#define SICR_ENET_CLKRT ((uint)0x0000003d) + +/* The MBX uses the 8259. +*/ +#define NR_8259_INTS 16 + +#endif /* !__ASSEMBLY__ */ +#endif /* __MACH_MBX_DEFS */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/mcpn765.c b/arch/ppc/platforms/mcpn765.c new file mode 100644 index 00000000000..e88d294ea59 --- /dev/null +++ b/arch/ppc/platforms/mcpn765.c @@ -0,0 +1,527 @@ +/* + * arch/ppc/platforms/mcpn765.c + * + * Board setup routines for the Motorola MCG MCPN765 cPCI Board. + * + * Author: Mark A. Greer + * mgreer@mvista.com + * + * Modified by Randy Vinson (rvinson@mvista.com) + * + * 2001-2002 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +/* + * This file adds support for the Motorola MCG MCPN765. + */ +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/major.h> +#include <linux/initrd.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/seq_file.h> +#include <linux/root_dev.h> +#include <linux/serial.h> +#include <linux/tty.h> /* for linux/serial_core.h */ +#include <linux/serial_core.h> +#include <linux/slab.h> + +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/time.h> +#include <asm/dma.h> +#include <asm/byteorder.h> +#include <asm/io.h> +#include <asm/machdep.h> +#include <asm/prom.h> +#include <asm/smp.h> +#include <asm/open_pic.h> +#include <asm/i8259.h> +#include <asm/todc.h> +#include <asm/pci-bridge.h> +#include <asm/irq.h> +#include <asm/uaccess.h> +#include <asm/bootinfo.h> +#include <asm/hawk.h> +#include <asm/kgdb.h> + +#include "mcpn765.h" + +static u_char mcpn765_openpic_initsenses[] __initdata = { + (IRQ_SENSE_EDGE | IRQ_POLARITY_POSITIVE),/* 16: i8259 cascade */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 17: COM1,2,3,4 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 18: Enet 1 (front) */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 19: HAWK WDT XXXX */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 20: 21554 bridge */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 21: cPCI INTA# */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 22: cPCI INTB# */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 23: cPCI INTC# */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 24: cPCI INTD# */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 25: PMC1 INTA#,PMC2 INTB#*/ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 26: PMC1 INTB#,PMC2 INTC#*/ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 27: PMC1 INTC#,PMC2 INTD#*/ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 28: PMC1 INTD#,PMC2 INTA#*/ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 29: Enet 2 (J3) */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 30: Abort Switch */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 31: RTC Alarm */ +}; + +extern void mcpn765_set_VIA_IDE_native(void); + +extern u_int openpic_irq(void); +extern char cmd_line[]; + +extern void gen550_progress(char *, unsigned short); +extern void gen550_init(int, struct uart_port *); + +int use_of_interrupt_tree = 0; + +static void mcpn765_halt(void); + +TODC_ALLOC(); + +/* + * Motorola MCG MCPN765 interrupt routing. + */ +static inline int +mcpn765_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + { 14, 0, 0, 0 }, /* IDSEL 11 - have to manually set */ + { 0, 0, 0, 0 }, /* IDSEL 12 - unused */ + { 0, 0, 0, 0 }, /* IDSEL 13 - unused */ + { 18, 0, 0, 0 }, /* IDSEL 14 - Enet 0 */ + { 0, 0, 0, 0 }, /* IDSEL 15 - unused */ + { 25, 26, 27, 28 }, /* IDSEL 16 - PMC Slot 1 */ + { 28, 25, 26, 27 }, /* IDSEL 17 - PMC Slot 2 */ + { 0, 0, 0, 0 }, /* IDSEL 18 - PMC 2B Connector XXXX */ + { 29, 0, 0, 0 }, /* IDSEL 19 - Enet 1 */ + { 20, 0, 0, 0 }, /* IDSEL 20 - 21554 cPCI bridge */ + }; + + const long min_idsel = 11, max_idsel = 20, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +} + +void __init +mcpn765_set_VIA_IDE_legacy(void) +{ + unsigned short vend, dev; + + early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_VENDOR_ID, &vend); + early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_DEVICE_ID, &dev); + + if ((vend == PCI_VENDOR_ID_VIA) && + (dev == PCI_DEVICE_ID_VIA_82C586_1)) { + + unsigned char temp; + + /* put back original "standard" port base addresses */ + early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1), + PCI_BASE_ADDRESS_0, 0x1f1); + early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1), + PCI_BASE_ADDRESS_1, 0x3f5); + early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1), + PCI_BASE_ADDRESS_2, 0x171); + early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1), + PCI_BASE_ADDRESS_3, 0x375); + early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1), + PCI_BASE_ADDRESS_4, 0xcc01); + + /* put into legacy mode */ + early_read_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG, + &temp); + temp &= ~0x05; + early_write_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG, + temp); + } +} + +void +mcpn765_set_VIA_IDE_native(void) +{ + unsigned short vend, dev; + + early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_VENDOR_ID, &vend); + early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_DEVICE_ID, &dev); + + if ((vend == PCI_VENDOR_ID_VIA) && + (dev == PCI_DEVICE_ID_VIA_82C586_1)) { + + unsigned char temp; + + /* put into native mode */ + early_read_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG, + &temp); + temp |= 0x05; + early_write_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG, + temp); + } +} + +/* + * Initialize the VIA 82c586b. + */ +static void __init +mcpn765_setup_via_82c586b(void) +{ + struct pci_dev *dev; + u_char c; + + if ((dev = pci_get_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_82C586_0, + NULL)) == NULL) { + printk("No VIA ISA bridge found\n"); + mcpn765_halt(); + /* NOTREACHED */ + } + + /* + * If the firmware left the EISA 4d0/4d1 ports enabled, make sure + * IRQ 14 is set for edge. + */ + pci_read_config_byte(dev, 0x47, &c); + + if (c & (1<<5)) { + c = inb(0x4d1); + c &= ~(1<<6); + outb(c, 0x4d1); + } + + /* Disable PNP IRQ routing since we use the Hawk's MPIC */ + pci_write_config_dword(dev, 0x54, 0); + pci_write_config_byte(dev, 0x58, 0); + + pci_dev_put(dev); + if ((dev = pci_get_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_82C586_1, + NULL)) == NULL) { + printk("No VIA ISA bridge found\n"); + mcpn765_halt(); + /* NOTREACHED */ + } + + /* + * PPCBug doesn't set the enable bits for the IDE device. + * Turn them on now. + */ + pci_read_config_byte(dev, 0x40, &c); + c |= 0x03; + pci_write_config_byte(dev, 0x40, c); + pci_dev_put(dev); + + return; +} + +void __init +mcpn765_pcibios_fixup(void) +{ + /* Do MCPN765 board specific initialization. */ + mcpn765_setup_via_82c586b(); +} + +void __init +mcpn765_find_bridges(void) +{ + struct pci_controller *hose; + + hose = pcibios_alloc_controller(); + + if (!hose) + return; + + hose->first_busno = 0; + hose->last_busno = 0xff; + hose->pci_mem_offset = MCPN765_PCI_PHY_MEM_OFFSET; + + pci_init_resource(&hose->io_resource, + MCPN765_PCI_IO_START, + MCPN765_PCI_IO_END, + IORESOURCE_IO, + "PCI host bridge"); + + pci_init_resource(&hose->mem_resources[0], + MCPN765_PCI_MEM_START, + MCPN765_PCI_MEM_END, + IORESOURCE_MEM, + "PCI host bridge"); + + hose->io_space.start = MCPN765_PCI_IO_START; + hose->io_space.end = MCPN765_PCI_IO_END; + hose->mem_space.start = MCPN765_PCI_MEM_START; + hose->mem_space.end = MCPN765_PCI_MEM_END - HAWK_MPIC_SIZE; + + if (hawk_init(hose, + MCPN765_HAWK_PPC_REG_BASE, + MCPN765_PROC_PCI_MEM_START, + MCPN765_PROC_PCI_MEM_END - HAWK_MPIC_SIZE, + MCPN765_PROC_PCI_IO_START, + MCPN765_PROC_PCI_IO_END, + MCPN765_PCI_MEM_END - HAWK_MPIC_SIZE + 1) != 0) { + printk("Could not initialize HAWK bridge\n"); + } + + /* VIA IDE BAR decoders are only 16-bits wide. PCI Auto Config + * will reassign the bars outside of 16-bit I/O space, which will + * "break" things. To prevent this, we'll set the IDE chip into + * legacy mode and seed the bars with their legacy addresses (in 16-bit + * I/O space). The Auto Config code will skip the IDE contoller in + * legacy mode, so our bar values will stick. + */ + mcpn765_set_VIA_IDE_legacy(); + + hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); + + /* Now that we've got 16-bit addresses in the bars, we can switch the + * IDE controller back into native mode so we can do "modern" resource + * and interrupt management. + */ + mcpn765_set_VIA_IDE_native(); + + ppc_md.pcibios_fixup = mcpn765_pcibios_fixup; + ppc_md.pcibios_fixup_bus = NULL; + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = mcpn765_map_irq; + + return; +} +static void __init +mcpn765_setup_arch(void) +{ + struct pci_controller *hose; + + if ( ppc_md.progress ) + ppc_md.progress("mcpn765_setup_arch: enter", 0); + + loops_per_jiffy = 50000000 / HZ; + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_SDA2; +#endif + + if ( ppc_md.progress ) + ppc_md.progress("mcpn765_setup_arch: find_bridges", 0); + + /* Lookup PCI host bridges */ + mcpn765_find_bridges(); + + hose = pci_bus_to_hose(0); + isa_io_base = (ulong)hose->io_base_virt; + + TODC_INIT(TODC_TYPE_MK48T37, + (MCPN765_PHYS_NVRAM_AS0 - isa_io_base), + (MCPN765_PHYS_NVRAM_AS1 - isa_io_base), + (MCPN765_PHYS_NVRAM_DATA - isa_io_base), + 8); + + OpenPIC_InitSenses = mcpn765_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof(mcpn765_openpic_initsenses); + + printk("Motorola MCG MCPN765 cPCI Non-System Board\n"); + printk("MCPN765 port (MontaVista Software, Inc. (source@mvista.com))\n"); + + if ( ppc_md.progress ) + ppc_md.progress("mcpn765_setup_arch: exit", 0); + + return; +} + +static void __init +mcpn765_init2(void) +{ + + request_region(0x00,0x20,"dma1"); + request_region(0x20,0x20,"pic1"); + request_region(0x40,0x20,"timer"); + request_region(0x80,0x10,"dma page reg"); + request_region(0xa0,0x20,"pic2"); + request_region(0xc0,0x20,"dma2"); + + return; +} + +/* + * Interrupt setup and service. + * Have MPIC on HAWK and cascaded 8259s on VIA 82586 cascaded to MPIC. + */ +static void __init +mcpn765_init_IRQ(void) +{ + int i; + + if ( ppc_md.progress ) + ppc_md.progress("init_irq: enter", 0); + + openpic_init(NUM_8259_INTERRUPTS); + openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade", + i8259_irq); + + for(i=0; i < NUM_8259_INTERRUPTS; i++) + irq_desc[i].handler = &i8259_pic; + + i8259_init(0); + + if ( ppc_md.progress ) + ppc_md.progress("init_irq: exit", 0); + + return; +} + +static u32 +mcpn765_irq_canonicalize(u32 irq) +{ + if (irq == 2) + return 9; + else + return irq; +} + +static unsigned long __init +mcpn765_find_end_of_memory(void) +{ + return hawk_get_mem_size(MCPN765_HAWK_SMC_BASE); +} + +static void __init +mcpn765_map_io(void) +{ + io_block_mapping(0xfe800000, 0xfe800000, 0x00800000, _PAGE_IO); +} + +static void +mcpn765_reset_board(void) +{ + local_irq_disable(); + + /* set VIA IDE controller into native mode */ + mcpn765_set_VIA_IDE_native(); + + /* Set exception prefix high - to the firmware */ + _nmask_and_or_msr(0, MSR_IP); + + out_8((u_char *)MCPN765_BOARD_MODRST_REG, 0x01); + + return; +} + +static void +mcpn765_restart(char *cmd) +{ + volatile ulong i = 10000000; + + mcpn765_reset_board(); + + while (i-- > 0); + panic("restart failed\n"); +} + +static void +mcpn765_power_off(void) +{ + mcpn765_halt(); + /* NOTREACHED */ +} + +static void +mcpn765_halt(void) +{ + local_irq_disable(); + while (1); + /* NOTREACHED */ +} + +static int +mcpn765_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "vendor\t\t: Motorola MCG\n"); + seq_printf(m, "machine\t\t: MCPN765\n"); + + return 0; +} + +/* + * Set BAT 3 to map 0xf0000000 to end of physical memory space. + */ +static __inline__ void +mcpn765_set_bat(void) +{ + mb(); + mtspr(SPRN_DBAT1U, 0xfe8000fe); + mtspr(SPRN_DBAT1L, 0xfe80002a); + mb(); +} + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + parse_bootinfo(find_bootinfo()); + + /* Map in board regs, etc. */ + mcpn765_set_bat(); + + isa_mem_base = MCPN765_ISA_MEM_BASE; + pci_dram_offset = MCPN765_PCI_DRAM_OFFSET; + ISA_DMA_THRESHOLD = 0x00ffffff; + DMA_MODE_READ = 0x44; + DMA_MODE_WRITE = 0x48; + + ppc_md.setup_arch = mcpn765_setup_arch; + ppc_md.show_cpuinfo = mcpn765_show_cpuinfo; + ppc_md.irq_canonicalize = mcpn765_irq_canonicalize; + ppc_md.init_IRQ = mcpn765_init_IRQ; + ppc_md.get_irq = openpic_get_irq; + ppc_md.init = mcpn765_init2; + + ppc_md.restart = mcpn765_restart; + ppc_md.power_off = mcpn765_power_off; + ppc_md.halt = mcpn765_halt; + + ppc_md.find_end_of_memory = mcpn765_find_end_of_memory; + ppc_md.setup_io_mappings = mcpn765_map_io; + + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.calibrate_decr = todc_calibrate_decr; + + ppc_md.nvram_read_val = todc_m48txx_read_val; + ppc_md.nvram_write_val = todc_m48txx_write_val; + + ppc_md.heartbeat = NULL; + ppc_md.heartbeat_reset = 0; + ppc_md.heartbeat_count = 0; + +#ifdef CONFIG_SERIAL_TEXT_DEBUG + ppc_md.progress = gen550_progress; +#endif +#ifdef CONFIG_KGDB + ppc_md.kgdb_map_scc = gen550_kgdb_map_scc; +#endif + + return; +} diff --git a/arch/ppc/platforms/mcpn765.h b/arch/ppc/platforms/mcpn765.h new file mode 100644 index 00000000000..4d35ecad097 --- /dev/null +++ b/arch/ppc/platforms/mcpn765.h @@ -0,0 +1,122 @@ +/* + * arch/ppc/platforms/mcpn765.h + * + * Definitions for Motorola MCG MCPN765 cPCI Board. + * + * Author: Mark A. Greer + * mgreer@mvista.com + * + * 2001-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. + */ + +/* + * From Processor to PCI: + * PCI Mem Space: 0x80000000 - 0xc0000000 -> 0x80000000 - 0xc0000000 (1 GB) + * PCI I/O Space: 0xfd800000 - 0xfe000000 -> 0x00000000 - 0x00800000 (8 MB) + * Note: Must skip 0xfe000000-0xfe400000 for CONFIG_HIGHMEM/PKMAP area + * MPIC in PCI Mem Space: 0xfe800000 - 0xfe830000 (not all used by MPIC) + * + * From PCI to Processor: + * System Memory: 0x00000000 -> 0x00000000 + */ + +#ifndef __PPC_PLATFORMS_MCPN765_H +#define __PPC_PLATFORMS_MCPN765_H +#include <linux/config.h> + +/* PCI Memory space mapping info */ +#define MCPN765_PCI_MEM_SIZE 0x40000000U +#define MCPN765_PROC_PCI_MEM_START 0x80000000U +#define MCPN765_PROC_PCI_MEM_END (MCPN765_PROC_PCI_MEM_START + \ + MCPN765_PCI_MEM_SIZE - 1) +#define MCPN765_PCI_MEM_START 0x80000000U +#define MCPN765_PCI_MEM_END (MCPN765_PCI_MEM_START + \ + MCPN765_PCI_MEM_SIZE - 1) + +/* PCI I/O space mapping info */ +#define MCPN765_PCI_IO_SIZE 0x00800000U +#define MCPN765_PROC_PCI_IO_START 0xfd800000U +#define MCPN765_PROC_PCI_IO_END (MCPN765_PROC_PCI_IO_START + \ + MCPN765_PCI_IO_SIZE - 1) +#define MCPN765_PCI_IO_START 0x00000000U +#define MCPN765_PCI_IO_END (MCPN765_PCI_IO_START + \ + MCPN765_PCI_IO_SIZE - 1) + +/* System memory mapping info */ +#define MCPN765_PCI_DRAM_OFFSET 0x00000000U +#define MCPN765_PCI_PHY_MEM_OFFSET 0x00000000U + +#define MCPN765_ISA_MEM_BASE 0x00000000U +#define MCPN765_ISA_IO_BASE MCPN765_PROC_PCI_IO_START + +/* Define base addresses for important sets of registers */ +#define MCPN765_HAWK_MPIC_BASE 0xfe800000U +#define MCPN765_HAWK_SMC_BASE 0xfef80000U +#define MCPN765_HAWK_PPC_REG_BASE 0xfeff0000U + +/* Define MCPN765 board register addresses. */ +#define MCPN765_BOARD_STATUS_REG 0xfef88080U +#define MCPN765_BOARD_MODFAIL_REG 0xfef88090U +#define MCPN765_BOARD_MODRST_REG 0xfef880a0U +#define MCPN765_BOARD_TBEN_REG 0xfef880c0U +#define MCPN765_BOARD_GEOGRAPHICAL_REG 0xfef880e8U +#define MCPN765_BOARD_EXT_FEATURE_REG 0xfef880f0U +#define MCPN765_BOARD_LAST_RESET_REG 0xfef880f8U + +/* Defines for UART */ + +/* Define the UART base addresses */ +#define MCPN765_SERIAL_1 0xfef88000 +#define MCPN765_SERIAL_2 0xfef88200 +#define MCPN765_SERIAL_3 0xfef88400 +#define MCPN765_SERIAL_4 0xfef88600 + +#ifdef CONFIG_SERIAL_MANY_PORTS +#define RS_TABLE_SIZE 64 +#else +#define RS_TABLE_SIZE 4 +#endif + +/* Rate for the 1.8432 Mhz clock for the onboard serial chip */ +#define BASE_BAUD ( 1843200 / 16 ) +#define UART_CLK 1843200 + +#ifdef CONFIG_SERIAL_DETECT_IRQ +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ) +#else +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST) +#endif + +/* All UART IRQ's are wire-OR'd to IRQ 17 */ +#define STD_SERIAL_PORT_DFNS \ + { 0, BASE_BAUD, MCPN765_SERIAL_1, 17, STD_COM_FLAGS, /* ttyS0 */\ + iomem_base: (u8 *)MCPN765_SERIAL_1, \ + iomem_reg_shift: 4, \ + io_type: SERIAL_IO_MEM }, \ + { 0, BASE_BAUD, MCPN765_SERIAL_2, 17, STD_COM_FLAGS, /* ttyS1 */\ + iomem_base: (u8 *)MCPN765_SERIAL_2, \ + iomem_reg_shift: 4, \ + io_type: SERIAL_IO_MEM }, \ + { 0, BASE_BAUD, MCPN765_SERIAL_3, 17, STD_COM_FLAGS, /* ttyS2 */\ + iomem_base: (u8 *)MCPN765_SERIAL_3, \ + iomem_reg_shift: 4, \ + io_type: SERIAL_IO_MEM }, \ + { 0, BASE_BAUD, MCPN765_SERIAL_4, 17, STD_COM_FLAGS, /* ttyS3 */\ + iomem_base: (u8 *)MCPN765_SERIAL_4, \ + iomem_reg_shift: 4, \ + io_type: SERIAL_IO_MEM }, + +#define SERIAL_PORT_DFNS \ + STD_SERIAL_PORT_DFNS + +/* Define the NVRAM/RTC address strobe & data registers */ +#define MCPN765_PHYS_NVRAM_AS0 0xfef880c8U +#define MCPN765_PHYS_NVRAM_AS1 0xfef880d0U +#define MCPN765_PHYS_NVRAM_DATA 0xfef880d8U + +extern void mcpn765_find_bridges(void); + +#endif /* __PPC_PLATFORMS_MCPN765_H */ diff --git a/arch/ppc/platforms/mpc5200.c b/arch/ppc/platforms/mpc5200.c new file mode 100644 index 00000000000..a58db438c16 --- /dev/null +++ b/arch/ppc/platforms/mpc5200.c @@ -0,0 +1,53 @@ +/* + * arch/ppc/platforms/mpc5200.c + * + * OCP Definitions for the boards based on MPC5200 processor. Contains + * definitions for every common peripherals. (Mostly all but PSCs) + * + * Maintainer : Sylvain Munaut <tnt@246tNt.com> + * + * Copyright 2004 Sylvain Munaut <tnt@246tNt.com> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <asm/ocp.h> +#include <asm/mpc52xx.h> + + +static struct ocp_fs_i2c_data mpc5200_i2c_def = { + .flags = FS_I2C_CLOCK_5200, +}; + + +/* Here is the core_ocp struct. + * With all the devices common to all board. Even if port multiplexing is + * not setup for them (if the user don't want them, just don't select the + * config option). The potentially conflicting devices (like PSCs) goes in + * board specific file. + */ +struct ocp_def core_ocp[] = { + { + .vendor = OCP_VENDOR_FREESCALE, + .function = OCP_FUNC_IIC, + .index = 0, + .paddr = MPC52xx_I2C1, + .irq = OCP_IRQ_NA, /* MPC52xx_IRQ_I2C1 - Buggy */ + .pm = OCP_CPM_NA, + .additions = &mpc5200_i2c_def, + }, + { + .vendor = OCP_VENDOR_FREESCALE, + .function = OCP_FUNC_IIC, + .index = 1, + .paddr = MPC52xx_I2C2, + .irq = OCP_IRQ_NA, /* MPC52xx_IRQ_I2C2 - Buggy */ + .pm = OCP_CPM_NA, + .additions = &mpc5200_i2c_def, + }, + { /* Terminating entry */ + .vendor = OCP_VENDOR_INVALID + } +}; diff --git a/arch/ppc/platforms/mvme5100.c b/arch/ppc/platforms/mvme5100.c new file mode 100644 index 00000000000..b292b44b760 --- /dev/null +++ b/arch/ppc/platforms/mvme5100.c @@ -0,0 +1,349 @@ +/* + * arch/ppc/platforms/mvme5100.c + * + * Board setup routines for the Motorola MVME5100. + * + * Author: Matt Porter <mporter@mvista.com> + * + * 2001-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. + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/pci.h> +#include <linux/initrd.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/ide.h> +#include <linux/seq_file.h> +#include <linux/kdev_t.h> +#include <linux/root_dev.h> + +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/machdep.h> +#include <asm/open_pic.h> +#include <asm/i8259.h> +#include <asm/todc.h> +#include <asm/pci-bridge.h> +#include <asm/bootinfo.h> +#include <asm/hawk.h> + +#include <platforms/pplus.h> +#include <platforms/mvme5100.h> + +static u_char mvme5100_openpic_initsenses[16] __initdata = { + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* i8259 cascade */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* TL16C550 UART 1,2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Enet1 front panel or P2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Hawk Watchdog 1,2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* DS1621 thermal alarm */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Universe II LINT0# */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Universe II LINT1# */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Universe II LINT2# */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Universe II LINT3# */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PMC1 INTA#, PMC2 INTB# */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PMC1 INTB#, PMC2 INTC# */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PMC1 INTC#, PMC2 INTD# */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PMC1 INTD#, PMC2 INTA# */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Enet 2 (front panel) */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Abort Switch */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* RTC Alarm */ +}; + +static inline int +mvme5100_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + int irq; + + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + { 0, 0, 0, 0 }, /* IDSEL 11 - Winbond */ + { 0, 0, 0, 0 }, /* IDSEL 12 - unused */ + { 21, 22, 23, 24 }, /* IDSEL 13 - Universe II */ + { 18, 0, 0, 0 }, /* IDSEL 14 - Enet 1 */ + { 0, 0, 0, 0 }, /* IDSEL 15 - unused */ + { 25, 26, 27, 28 }, /* IDSEL 16 - PMC Slot 1 */ + { 28, 25, 26, 27 }, /* IDSEL 17 - PMC Slot 2 */ + { 0, 0, 0, 0 }, /* IDSEL 18 - unused */ + { 29, 0, 0, 0 }, /* IDSEL 19 - Enet 2 */ + { 0, 0, 0, 0 }, /* IDSEL 20 - PMCSPAN */ + }; + + const long min_idsel = 11, max_idsel = 20, irqs_per_slot = 4; + irq = PCI_IRQ_TABLE_LOOKUP; + /* If lookup is zero, always return 0 */ + if (!irq) + return 0; + else +#ifdef CONFIG_MVME5100_IPMC761_PRESENT + /* If IPMC761 present, return table value */ + return irq; +#else + /* If IPMC761 not present, we don't have an i8259 so adjust */ + return (irq - NUM_8259_INTERRUPTS); +#endif +} + +static void +mvme5100_pcibios_fixup_resources(struct pci_dev *dev) +{ + int i; + + if ((dev->vendor == PCI_VENDOR_ID_MOTOROLA) && + (dev->device == PCI_DEVICE_ID_MOTOROLA_HAWK)) + for (i=0; i<DEVICE_COUNT_RESOURCE; i++) + { + dev->resource[i].start = 0; + dev->resource[i].end = 0; + } +} + +static void __init +mvme5100_setup_bridge(void) +{ + struct pci_controller* hose; + + hose = pcibios_alloc_controller(); + + if (!hose) + return; + + hose->first_busno = 0; + hose->last_busno = 0xff; + hose->pci_mem_offset = MVME5100_PCI_MEM_OFFSET; + + pci_init_resource(&hose->io_resource, MVME5100_PCI_LOWER_IO, + MVME5100_PCI_UPPER_IO, IORESOURCE_IO, + "PCI host bridge"); + + pci_init_resource(&hose->mem_resources[0], MVME5100_PCI_LOWER_MEM, + MVME5100_PCI_UPPER_MEM, IORESOURCE_MEM, + "PCI host bridge"); + + hose->io_space.start = MVME5100_PCI_LOWER_IO; + hose->io_space.end = MVME5100_PCI_UPPER_IO; + hose->mem_space.start = MVME5100_PCI_LOWER_MEM; + hose->mem_space.end = MVME5100_PCI_UPPER_MEM; + hose->io_base_virt = (void *)MVME5100_ISA_IO_BASE; + + /* Use indirect method of Hawk */ + setup_indirect_pci(hose, MVME5100_PCI_CONFIG_ADDR, + MVME5100_PCI_CONFIG_DATA); + + hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); + + ppc_md.pcibios_fixup_resources = mvme5100_pcibios_fixup_resources; + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = mvme5100_map_irq; +} + +static void __init +mvme5100_setup_arch(void) +{ + if ( ppc_md.progress ) + ppc_md.progress("mvme5100_setup_arch: enter", 0); + + loops_per_jiffy = 50000000 / HZ; + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_SDA2; +#endif + + if ( ppc_md.progress ) + ppc_md.progress("mvme5100_setup_arch: find_bridges", 0); + + /* Setup PCI host bridge */ + mvme5100_setup_bridge(); + + /* Find and map our OpenPIC */ + hawk_mpic_init(MVME5100_PCI_MEM_OFFSET); + OpenPIC_InitSenses = mvme5100_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof(mvme5100_openpic_initsenses); + + printk("MVME5100 port (C) 2001 MontaVista Software, Inc. (source@mvista.com)\n"); + + if ( ppc_md.progress ) + ppc_md.progress("mvme5100_setup_arch: exit", 0); + + return; +} + +static void __init +mvme5100_init2(void) +{ +#ifdef CONFIG_MVME5100_IPMC761_PRESENT + request_region(0x00,0x20,"dma1"); + request_region(0x20,0x20,"pic1"); + request_region(0x40,0x20,"timer"); + request_region(0x80,0x10,"dma page reg"); + request_region(0xa0,0x20,"pic2"); + request_region(0xc0,0x20,"dma2"); +#endif + return; +} + +/* + * Interrupt setup and service. + * Have MPIC on HAWK and cascaded 8259s on Winbond cascaded to MPIC. + */ +static void __init +mvme5100_init_IRQ(void) +{ +#ifdef CONFIG_MVME5100_IPMC761_PRESENT + int i; +#endif + + if ( ppc_md.progress ) + ppc_md.progress("init_irq: enter", 0); + + openpic_set_sources(0, 16, OpenPIC_Addr + 0x10000); +#ifdef CONFIG_MVME5100_IPMC761_PRESENT + openpic_init(NUM_8259_INTERRUPTS); + openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade", + &i8259_irq); + + /* Map i8259 interrupts. */ + for (i = 0; i < NUM_8259_INTERRUPTS; i++) + irq_desc[i].handler = &i8259_pic; + + i8259_init(0); +#else + openpic_init(0); +#endif + + if ( ppc_md.progress ) + ppc_md.progress("init_irq: exit", 0); + + return; +} + +/* + * Set BAT 3 to map 0xf0000000 to end of physical memory space. + */ +static __inline__ void +mvme5100_set_bat(void) +{ + mb(); + mtspr(SPRN_DBAT1U, 0xf0001ffe); + mtspr(SPRN_DBAT1L, 0xf000002a); + mb(); +} + +static unsigned long __init +mvme5100_find_end_of_memory(void) +{ + return hawk_get_mem_size(MVME5100_HAWK_SMC_BASE); +} + +static void __init +mvme5100_map_io(void) +{ + io_block_mapping(0xfe000000, 0xfe000000, 0x02000000, _PAGE_IO); + ioremap_base = 0xfe000000; +} + +static void +mvme5100_reset_board(void) +{ + local_irq_disable(); + + /* Set exception prefix high - to the firmware */ + _nmask_and_or_msr(0, MSR_IP); + + out_8((u_char *)MVME5100_BOARD_MODRST_REG, 0x01); + + return; +} + +static void +mvme5100_restart(char *cmd) +{ + volatile ulong i = 10000000; + + mvme5100_reset_board(); + + while (i-- > 0); + panic("restart failed\n"); +} + +static void +mvme5100_halt(void) +{ + local_irq_disable(); + while (1); +} + +static void +mvme5100_power_off(void) +{ + mvme5100_halt(); +} + +static int +mvme5100_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "vendor\t\t: Motorola\n"); + seq_printf(m, "machine\t\t: MVME5100\n"); + + return 0; +} + +TODC_ALLOC(); + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + parse_bootinfo(find_bootinfo()); + mvme5100_set_bat(); + + isa_io_base = MVME5100_ISA_IO_BASE; + isa_mem_base = MVME5100_ISA_MEM_BASE; + pci_dram_offset = MVME5100_PCI_DRAM_OFFSET; + + ppc_md.setup_arch = mvme5100_setup_arch; + ppc_md.show_cpuinfo = mvme5100_show_cpuinfo; + ppc_md.init_IRQ = mvme5100_init_IRQ; + ppc_md.get_irq = openpic_get_irq; + ppc_md.init = mvme5100_init2; + + ppc_md.restart = mvme5100_restart; + ppc_md.power_off = mvme5100_power_off; + ppc_md.halt = mvme5100_halt; + + ppc_md.find_end_of_memory = mvme5100_find_end_of_memory; + ppc_md.setup_io_mappings = mvme5100_map_io; + + TODC_INIT(TODC_TYPE_MK48T37, MVME5100_NVRAM_AS0, MVME5100_NVRAM_AS1, + MVME5100_NVRAM_DATA, 8); + + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.calibrate_decr = todc_calibrate_decr; + + ppc_md.nvram_read_val = todc_m48txx_read_val; + ppc_md.nvram_write_val = todc_m48txx_write_val; +} diff --git a/arch/ppc/platforms/mvme5100.h b/arch/ppc/platforms/mvme5100.h new file mode 100644 index 00000000000..edd479439a4 --- /dev/null +++ b/arch/ppc/platforms/mvme5100.h @@ -0,0 +1,91 @@ +/* + * include/asm-ppc/platforms/mvme5100.h + * + * Definitions for Motorola MVME5100. + * + * Author: Matt Porter <mporter@mvista.com> + * + * 2001 (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. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_MVME5100_H__ +#define __ASM_MVME5100_H__ + +#define MVME5100_HAWK_SMC_BASE 0xfef80000 + +#define MVME5100_PCI_CONFIG_ADDR 0xfe000cf8 +#define MVME5100_PCI_CONFIG_DATA 0xfe000cfc + +#define MVME5100_PCI_IO_BASE 0xfe000000 +#define MVME5100_PCI_MEM_BASE 0x80000000 + +#define MVME5100_PCI_MEM_OFFSET 0x00000000 + +#define MVME5100_PCI_DRAM_OFFSET 0x00000000 +#define MVME5100_ISA_MEM_BASE 0x00000000 +#define MVME5100_ISA_IO_BASE MVME5100_PCI_IO_BASE + +#define MVME5100_PCI_LOWER_MEM 0x80000000 +#define MVME5100_PCI_UPPER_MEM 0xf3f7ffff +#define MVME5100_PCI_LOWER_IO 0x00000000 +#define MVME5100_PCI_UPPER_IO 0x0077ffff + +/* MVME5100 board register addresses. */ +#define MVME5100_BOARD_STATUS_REG 0xfef88080 +#define MVME5100_BOARD_MODFAIL_REG 0xfef88090 +#define MVME5100_BOARD_MODRST_REG 0xfef880a0 +#define MVME5100_BOARD_TBEN_REG 0xfef880c0 +#define MVME5100_BOARD_SW_READ_REG 0xfef880e0 +#define MVME5100_BOARD_GEO_ADDR_REG 0xfef880e8 +#define MVME5100_BOARD_EXT_FEATURE1_REG 0xfef880f0 +#define MVME5100_BOARD_EXT_FEATURE2_REG 0xfef88100 + +/* Define the NVRAM/RTC address strobe & data registers */ +#define MVME5100_PHYS_NVRAM_AS0 0xfef880c8 +#define MVME5100_PHYS_NVRAM_AS1 0xfef880d0 +#define MVME5100_PHYS_NVRAM_DATA 0xfef880d8 + +#define MVME5100_NVRAM_AS0 (MVME5100_PHYS_NVRAM_AS0 - MVME5100_ISA_IO_BASE) +#define MVME5100_NVRAM_AS1 (MVME5100_PHYS_NVRAM_AS1 - MVME5100_ISA_IO_BASE) +#define MVME5100_NVRAM_DATA (MVME5100_PHYS_NVRAM_DATA - MVME5100_ISA_IO_BASE) + +/* UART clock, addresses, and irq */ +#define MVME5100_BASE_BAUD 1843200 +#define MVME5100_SERIAL_1 0xfef88000 +#define MVME5100_SERIAL_2 0xfef88200 +#ifdef CONFIG_MVME5100_IPMC761_PRESENT +#define MVME5100_SERIAL_IRQ 17 +#else +#define MVME5100_SERIAL_IRQ 1 +#endif + +#define RS_TABLE_SIZE 4 + +#define BASE_BAUD ( MVME5100_BASE_BAUD / 16 ) + +#define STD_COM_FLAGS ASYNC_BOOT_AUTOCONF + +/* All UART IRQ's are wire-OR'd to one MPIC IRQ */ +#define STD_SERIAL_PORT_DFNS \ + { 0, BASE_BAUD, MVME5100_SERIAL_1, \ + MVME5100_SERIAL_IRQ, \ + STD_COM_FLAGS, /* ttyS0 */ \ + iomem_base: (unsigned char *)MVME5100_SERIAL_1, \ + iomem_reg_shift: 4, \ + io_type: SERIAL_IO_MEM }, \ + { 0, BASE_BAUD, MVME5100_SERIAL_2, \ + MVME5100_SERIAL_IRQ, \ + STD_COM_FLAGS, /* ttyS1 */ \ + iomem_base: (unsigned char *)MVME5100_SERIAL_2, \ + iomem_reg_shift: 4, \ + io_type: SERIAL_IO_MEM }, + +#define SERIAL_PORT_DFNS \ + STD_SERIAL_PORT_DFNS + +#endif /* __ASM_MVME5100_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/pal4.h b/arch/ppc/platforms/pal4.h new file mode 100644 index 00000000000..641a11a3165 --- /dev/null +++ b/arch/ppc/platforms/pal4.h @@ -0,0 +1,42 @@ +/* + * arch/ppc/platforms/pal4.h + * + * Definitions for SBS Palomar IV board + * + * Author: Dan Cox + * + * 2002 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#ifndef __PPC_PLATFORMS_PAL4_H +#define __PPC_PLATFORMS_PAL4_H + +#define PAL4_NVRAM 0xfffc0000 +#define PAL4_NVRAM_SIZE 0x8000 + +#define PAL4_DRAM 0xfff80000 +#define PAL4_DRAM_BR_MASK 0xc0 +#define PAL4_DRAM_BR_SHIFT 6 +#define PAL4_DRAM_RESET 0x10 +#define PAL4_DRAM_EREADY 0x40 + +#define PAL4_MISC 0xfff80004 +#define PAL4_MISC_FB_MASK 0xc0 +#define PAL4_MISC_FLASH 0x20 /* StratFlash mapping: 1->0xff80, 0->0xfff0 */ +#define PAL4_MISC_MISC 0x08 +#define PAL4_MISC_BITF 0x02 +#define PAL4_MISC_NVKS 0x01 + +#define PAL4_L2 0xfff80008 +#define PAL4_L2_MASK 0x07 + +#define PAL4_PLDR 0xfff8000c + +/* Only two Ethernet devices on the board... */ +#define PAL4_ETH 31 +#define PAL4_INTA 20 + +#endif /* __PPC_PLATFORMS_PAL4_H */ diff --git a/arch/ppc/platforms/pal4_pci.c b/arch/ppc/platforms/pal4_pci.c new file mode 100644 index 00000000000..c3b1b757a48 --- /dev/null +++ b/arch/ppc/platforms/pal4_pci.c @@ -0,0 +1,77 @@ +/* + * arch/ppc/platforms/pal4_pci.c + * + * PCI support for SBS Palomar IV + * + * Author: Dan Cox + * + * 2002 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/pci.h> + +#include <asm/byteorder.h> +#include <asm/machdep.h> +#include <asm/io.h> +#include <asm/pci-bridge.h> +#include <asm/uaccess.h> + +#include <syslib/cpc700.h> + +#include "pal4.h" + +/* not much to this.... */ +static inline int __init +pal4_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + if (idsel == 9) + return PAL4_ETH; + else + return PAL4_INTA + (idsel - 3); +} + +void __init +pal4_find_bridges(void) +{ + struct pci_controller *hose; + + hose = pcibios_alloc_controller(); + if (!hose) + return; + + hose->first_busno = 0; + hose->last_busno = 0xff; + hose->pci_mem_offset = 0; + + /* Could snatch these from the CPC700.... */ + pci_init_resource(&hose->io_resource, + 0x0, + 0x03ffffff, + IORESOURCE_IO, + "PCI host bridge"); + + pci_init_resource(&hose->mem_resources[0], + 0x90000000, + 0x9fffffff, + IORESOURCE_MEM, + "PCI host bridge"); + + hose->io_space.start = 0x00800000; + hose->io_space.end = 0x03ffffff; + hose->mem_space.start = 0x90000000; + hose->mem_space.end = 0x9fffffff; + hose->io_base_virt = (void *) 0xf8000000; + + setup_indirect_pci(hose, CPC700_PCI_CONFIG_ADDR, + CPC700_PCI_CONFIG_DATA); + + hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); + + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = pal4_map_irq; +} diff --git a/arch/ppc/platforms/pal4_serial.h b/arch/ppc/platforms/pal4_serial.h new file mode 100644 index 00000000000..a715c66e1ad --- /dev/null +++ b/arch/ppc/platforms/pal4_serial.h @@ -0,0 +1,39 @@ +/* + * arch/ppc/platforms/pal4_serial.h + * + * Definitions for SBS PalomarIV serial support + * + * Author: Dan Cox + * + * 2002 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#ifndef __PPC_PAL4_SERIAL_H +#define __PPC_PAL4_SERIAL_H + +#define CPC700_SERIAL_1 0xff600300 +#define CPC700_SERIAL_2 0xff600400 + +#define RS_TABLE_SIZE 2 +#define BASE_BAUD (33333333 / 4 / 16) + +#ifdef CONFIG_SERIAL_DETECT_IRQ +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ) +#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ) +#else +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST) +#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF) +#endif + +#define SERIAL_PORT_DFNS \ + {0, BASE_BAUD, CPC700_SERIAL_1, 3, STD_COM_FLAGS, \ + iomem_base: (unsigned char *) CPC700_SERIAL_1, \ + io_type: SERIAL_IO_MEM}, /* ttyS0 */ \ + {0, BASE_BAUD, CPC700_SERIAL_2, 4, STD_COM_FLAGS, \ + iomem_base: (unsigned char *) CPC700_SERIAL_2, \ + io_type: SERIAL_IO_MEM} + +#endif diff --git a/arch/ppc/platforms/pal4_setup.c b/arch/ppc/platforms/pal4_setup.c new file mode 100644 index 00000000000..12446b93e38 --- /dev/null +++ b/arch/ppc/platforms/pal4_setup.c @@ -0,0 +1,175 @@ +/* + * arch/ppc/platforms/pal4_setup.c + * + * Board setup routines for the SBS PalomarIV. + * + * Author: Dan Cox + * + * 2002 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/time.h> +#include <linux/irq.h> +#include <linux/kdev_t.h> +#include <linux/initrd.h> +#include <linux/console.h> +#include <linux/seq_file.h> +#include <linux/root_dev.h> + +#include <asm/io.h> +#include <asm/todc.h> +#include <asm/bootinfo.h> + +#include <syslib/cpc700.h> + +#include "pal4.h" + +extern void pal4_find_bridges(void); + +unsigned int cpc700_irq_assigns[][2] = { + {1, 1}, /* IRQ 0: ECC correctable error */ + {1, 1}, /* IRQ 1: PCI write to memory range */ + {0, 1}, /* IRQ 2: PCI write to command register */ + {0, 1}, /* IRQ 3: UART 0 */ + {0, 1}, /* IRQ 4: UART 1 */ + {0, 1}, /* IRQ 5: ICC 0 */ + {0, 1}, /* IRQ 6: ICC 1 */ + {0, 1}, /* IRQ 7: GPT compare 0 */ + {0, 1}, /* IRQ 8: GPT compare 1 */ + {0, 1}, /* IRQ 9: GPT compare 2 */ + {0, 1}, /* IRQ 10: GPT compare 3 */ + {0, 1}, /* IRQ 11: GPT compare 4 */ + {0, 1}, /* IRQ 12: GPT capture 0 */ + {0, 1}, /* IRQ 13: GPT capture 1 */ + {0, 1}, /* IRQ 14: GPT capture 2 */ + {0, 1}, /* IRQ 15: GPT capture 3 */ + {0, 1}, /* IRQ 16: GPT capture 4 */ + {0, 0}, /* IRQ 17: reserved */ + {0, 0}, /* IRQ 18: reserved */ + {0, 0}, /* IRQ 19: reserved */ + {0, 0}, /* IRQ 20: reserved */ + {0, 1}, /* IRQ 21: Ethernet */ + {0, 0}, /* IRQ 22: reserved */ + {0, 0}, /* IRQ 23: reserved */ + {0, 0}, /* IRQ 24: resreved */ + {0, 0}, /* IRQ 25: reserved */ + {0, 0}, /* IRQ 26: reserved */ + {0, 0}, /* IRQ 27: reserved */ + {0, 0}, /* IRQ 28: reserved */ + {0, 0}, /* IRQ 29: reserved */ + {0, 0}, /* IRQ 30: reserved */ + {0, 0}, /* IRQ 31: reserved */ +}; + +static int +pal4_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "board\t\t: SBS Palomar IV\n"); + + return 0; +} + +static void +pal4_restart(char *cmd) +{ + local_irq_disable(); + __asm__ __volatile__("lis 3,0xfff0\n \ + ori 3,3,0x100\n \ + mtspr 26,3\n \ + li 3,0\n \ + mtspr 27,3\n \ + rfi"); + + for(;;); +} + +static void +pal4_power_off(void) +{ + local_irq_disable(); + for(;;); +} + +static void +pal4_halt(void) +{ + pal4_power_off(); +} + +TODC_ALLOC(); + +static void __init +pal4_setup_arch(void) +{ + unsigned long l2; + + TODC_INIT(TODC_TYPE_MK48T37, 0, 0, + ioremap(PAL4_NVRAM, PAL4_NVRAM_SIZE), 8); + + pal4_find_bridges(); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif + ROOT_DEV = Root_NFS; + + /* The L2 gets disabled in the bootloader, but all the proper + bits should be present from the fw, so just re-enable it */ + l2 = _get_L2CR(); + if (!(l2 & L2CR_L2E)) { + /* presume that it was initially set if the size is + still present. */ + if (l2 ^ L2CR_L2SIZ_MASK) + _set_L2CR(l2 | L2CR_L2E); + else + printk("L2 not set by firmware; left disabled.\n"); + } +} + +static void __init +pal4_map_io(void) +{ + io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO); +} + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + parse_bootinfo(find_bootinfo()); + + isa_io_base = 0 /*PAL4_ISA_IO_BASE*/; + pci_dram_offset = 0 /*PAL4_PCI_SYS_MEM_BASE*/; + + ppc_md.setup_arch = pal4_setup_arch; + ppc_md.show_cpuinfo = pal4_show_cpuinfo; + + ppc_md.setup_io_mappings = pal4_map_io; + + ppc_md.init_IRQ = cpc700_init_IRQ; + ppc_md.get_irq = cpc700_get_irq; + + ppc_md.restart = pal4_restart; + ppc_md.halt = pal4_halt; + ppc_md.power_off = pal4_power_off; + + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.calibrate_decr = todc_calibrate_decr; + + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; +} + diff --git a/arch/ppc/platforms/pcore.c b/arch/ppc/platforms/pcore.c new file mode 100644 index 00000000000..d7191630a65 --- /dev/null +++ b/arch/ppc/platforms/pcore.c @@ -0,0 +1,352 @@ +/* + * arch/ppc/platforms/pcore_setup.c + * + * Setup routines for Force PCORE boards + * + * Author: Matt Porter <mporter@mvista.com> + * + * 2001 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/types.h> +#include <linux/major.h> +#include <linux/initrd.h> +#include <linux/console.h> +#include <linux/irq.h> +#include <linux/seq_file.h> +#include <linux/root_dev.h> + +#include <asm/io.h> +#include <asm/machdep.h> +#include <asm/time.h> +#include <asm/i8259.h> +#include <asm/mpc10x.h> +#include <asm/todc.h> +#include <asm/bootinfo.h> +#include <asm/kgdb.h> + +#include "pcore.h" + +extern unsigned long loops_per_jiffy; + +static int board_type; + +static inline int __init +pcore_6750_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {9, 10, 11, 12}, /* IDSEL 24 - DEC 21554 */ + {10, 0, 0, 0}, /* IDSEL 25 - DEC 21143 */ + {11, 12, 9, 10}, /* IDSEL 26 - PMC I */ + {12, 9, 10, 11}, /* IDSEL 27 - PMC II */ + {0, 0, 0, 0}, /* IDSEL 28 - unused */ + {0, 0, 9, 0}, /* IDSEL 29 - unused */ + {0, 0, 0, 0}, /* IDSEL 30 - Winbond */ + }; + const long min_idsel = 24, max_idsel = 30, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +}; + +static inline int __init +pcore_680_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {9, 10, 11, 12}, /* IDSEL 24 - Sentinel */ + {10, 0, 0, 0}, /* IDSEL 25 - i82559 #1 */ + {11, 12, 9, 10}, /* IDSEL 26 - PMC I */ + {12, 9, 10, 11}, /* IDSEL 27 - PMC II */ + {9, 0, 0, 0}, /* IDSEL 28 - i82559 #2 */ + {0, 0, 0, 0}, /* IDSEL 29 - unused */ + {0, 0, 0, 0}, /* IDSEL 30 - Winbond */ + }; + const long min_idsel = 24, max_idsel = 30, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +}; + +void __init +pcore_pcibios_fixup(void) +{ + struct pci_dev *dev; + + if ((dev = pci_get_device(PCI_VENDOR_ID_WINBOND, + PCI_DEVICE_ID_WINBOND_83C553, + 0))) + { + /* Reroute interrupts both IDE channels to 15 */ + pci_write_config_byte(dev, + PCORE_WINBOND_IDE_INT, + 0xff); + + /* Route INTA-D to IRQ9-12, respectively */ + pci_write_config_word(dev, + PCORE_WINBOND_PCI_INT, + 0x9abc); + + /* + * Set up 8259 edge/level triggering + */ + outb(0x00, PCORE_WINBOND_PRI_EDG_LVL); + outb(0x1e, PCORE_WINBOND_SEC_EDG_LVL); + pci_dev_put(dev); + } +} + +int __init +pcore_find_bridges(void) +{ + struct pci_controller* hose; + int host_bridge, board_type; + + hose = pcibios_alloc_controller(); + if (!hose) + return 0; + + mpc10x_bridge_init(hose, + MPC10X_MEM_MAP_B, + MPC10X_MEM_MAP_B, + MPC10X_MAPB_EUMB_BASE); + + /* Determine board type */ + early_read_config_dword(hose, + 0, + PCI_DEVFN(0,0), + PCI_VENDOR_ID, + &host_bridge); + if (host_bridge == MPC10X_BRIDGE_106) + board_type = PCORE_TYPE_6750; + else /* MPC10X_BRIDGE_107 */ + board_type = PCORE_TYPE_680; + + hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); + + ppc_md.pcibios_fixup = pcore_pcibios_fixup; + ppc_md.pci_swizzle = common_swizzle; + + if (board_type == PCORE_TYPE_6750) + ppc_md.pci_map_irq = pcore_6750_map_irq; + else /* PCORE_TYPE_680 */ + ppc_md.pci_map_irq = pcore_680_map_irq; + + return board_type; +} + +/* Dummy variable to satisfy mpc10x_common.o */ +void *OpenPIC_Addr; + +static int +pcore_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "vendor\t\t: Force Computers\n"); + + if (board_type == PCORE_TYPE_6750) + seq_printf(m, "machine\t\t: PowerCore 6750\n"); + else /* PCORE_TYPE_680 */ + seq_printf(m, "machine\t\t: PowerCore 680\n"); + + seq_printf(m, "L2\t\t: " ); + if (board_type == PCORE_TYPE_6750) + switch (readb(PCORE_DCCR_REG) & PCORE_DCCR_L2_MASK) + { + case PCORE_DCCR_L2_0KB: + seq_printf(m, "nocache"); + break; + case PCORE_DCCR_L2_256KB: + seq_printf(m, "256KB"); + break; + case PCORE_DCCR_L2_1MB: + seq_printf(m, "1MB"); + break; + case PCORE_DCCR_L2_512KB: + seq_printf(m, "512KB"); + break; + default: + seq_printf(m, "error"); + break; + } + else /* PCORE_TYPE_680 */ + switch (readb(PCORE_DCCR_REG) & PCORE_DCCR_L2_MASK) + { + case PCORE_DCCR_L2_2MB: + seq_printf(m, "2MB"); + break; + case PCORE_DCCR_L2_256KB: + seq_printf(m, "reserved"); + break; + case PCORE_DCCR_L2_1MB: + seq_printf(m, "1MB"); + break; + case PCORE_DCCR_L2_512KB: + seq_printf(m, "512KB"); + break; + default: + seq_printf(m, "error"); + break; + } + + seq_printf(m, "\n"); + + return 0; +} + +static void __init +pcore_setup_arch(void) +{ + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000/HZ; + + /* Lookup PCI host bridges */ + board_type = pcore_find_bridges(); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_SDA2; +#endif + + printk(KERN_INFO "Force PowerCore "); + if (board_type == PCORE_TYPE_6750) + printk("6750\n"); + else + printk("680\n"); + printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n"); + _set_L2CR(L2CR_L2E | _get_L2CR()); + +} + +static void +pcore_restart(char *cmd) +{ + local_irq_disable(); + /* Hard reset */ + writeb(0x11, 0xfe000332); + while(1); +} + +static void +pcore_halt(void) +{ + local_irq_disable(); + /* Turn off user LEDs */ + writeb(0x00, 0xfe000300); + while (1); +} + +static void +pcore_power_off(void) +{ + pcore_halt(); +} + + +static void __init +pcore_init_IRQ(void) +{ + int i; + + for ( i = 0 ; i < 16 ; i++ ) + irq_desc[i].handler = &i8259_pic; + + i8259_init(0); +} + +/* + * Set BAT 3 to map 0xf0000000 to end of physical memory space. + */ +static __inline__ void +pcore_set_bat(void) +{ + mb(); + mtspr(SPRN_DBAT3U, 0xf0001ffe); + mtspr(SPRN_DBAT3L, 0xfe80002a); + mb(); + +} + +static unsigned long __init +pcore_find_end_of_memory(void) +{ + + return mpc10x_get_mem_size(MPC10X_MEM_MAP_B); +} + +static void __init +pcore_map_io(void) +{ + io_block_mapping(0xfe000000, 0xfe000000, 0x02000000, _PAGE_IO); +} + +TODC_ALLOC(); + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + parse_bootinfo(find_bootinfo()); + + /* Cover I/O space with a BAT */ + /* yuck, better hope your ram size is a power of 2 -- paulus */ + pcore_set_bat(); + + isa_io_base = MPC10X_MAPB_ISA_IO_BASE; + isa_mem_base = MPC10X_MAPB_ISA_MEM_BASE; + pci_dram_offset = MPC10X_MAPB_DRAM_OFFSET; + + ppc_md.setup_arch = pcore_setup_arch; + ppc_md.show_cpuinfo = pcore_show_cpuinfo; + ppc_md.init_IRQ = pcore_init_IRQ; + ppc_md.get_irq = i8259_irq; + + ppc_md.find_end_of_memory = pcore_find_end_of_memory; + ppc_md.setup_io_mappings = pcore_map_io; + + ppc_md.restart = pcore_restart; + ppc_md.power_off = pcore_power_off; + ppc_md.halt = pcore_halt; + + TODC_INIT(TODC_TYPE_MK48T59, + PCORE_NVRAM_AS0, + PCORE_NVRAM_AS1, + PCORE_NVRAM_DATA, + 8); + + ppc_md.time_init = todc_time_init; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.calibrate_decr = todc_calibrate_decr; + + ppc_md.nvram_read_val = todc_m48txx_read_val; + ppc_md.nvram_write_val = todc_m48txx_write_val; + +#ifdef CONFIG_SERIAL_TEXT_DEBUG + ppc_md.progress = gen550_progress; +#endif +#ifdef CONFIG_KGDB + ppc_md.kgdb_map_scc = gen550_kgdb_map_scc; +#endif +} diff --git a/arch/ppc/platforms/pcore.h b/arch/ppc/platforms/pcore.h new file mode 100644 index 00000000000..c6a26e76492 --- /dev/null +++ b/arch/ppc/platforms/pcore.h @@ -0,0 +1,39 @@ +/* + * arch/ppc/platforms/pcore.h + * + * Definitions for Force PowerCore board support + * + * Author: Matt Porter <mporter@mvista.com> + * + * 2001 (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. + */ + +#ifndef __PPC_PLATFORMS_PCORE_H +#define __PPC_PLATFORMS_PCORE_H + +#include <asm/mpc10x.h> + +#define PCORE_TYPE_6750 1 +#define PCORE_TYPE_680 2 + +#define PCORE_NVRAM_AS0 0x73 +#define PCORE_NVRAM_AS1 0x75 +#define PCORE_NVRAM_DATA 0x77 + +#define PCORE_DCCR_REG (MPC10X_MAPB_ISA_IO_BASE + 0x308) +#define PCORE_DCCR_L2_MASK 0xc0 +#define PCORE_DCCR_L2_0KB 0x00 +#define PCORE_DCCR_L2_256KB 0x40 +#define PCORE_DCCR_L2_512KB 0xc0 +#define PCORE_DCCR_L2_1MB 0x80 +#define PCORE_DCCR_L2_2MB 0x00 + +#define PCORE_WINBOND_IDE_INT 0x43 +#define PCORE_WINBOND_PCI_INT 0x44 +#define PCORE_WINBOND_PRI_EDG_LVL 0x4d0 +#define PCORE_WINBOND_SEC_EDG_LVL 0x4d1 + +#endif /* __PPC_PLATFORMS_PCORE_H */ diff --git a/arch/ppc/platforms/pcu_e.h b/arch/ppc/platforms/pcu_e.h new file mode 100644 index 00000000000..91a820a6fbc --- /dev/null +++ b/arch/ppc/platforms/pcu_e.h @@ -0,0 +1,28 @@ +/* + * Siemens PCU E board specific definitions + * + * Copyright (c) 2001 Wolfgang Denk (wd@denx.de) + */ + +#ifndef __MACH_PCU_E_H +#define __MACH_PCU_E_H + +#include <linux/config.h> + +#include <asm/ppcboot.h> + +#define PCU_E_IMMR_BASE 0xFE000000 /* phys. addr of IMMR */ +#define PCU_E_IMAP_SIZE (64 * 1024) /* size of mapped area */ + +#define IMAP_ADDR PCU_E_IMMR_BASE /* physical base address of IMMR area */ +#define IMAP_SIZE PCU_E_IMAP_SIZE /* mapped size of IMMR area */ + +#define FEC_INTERRUPT 15 /* = SIU_LEVEL7 */ +#define DEC_INTERRUPT 13 /* = SIU_LEVEL6 */ +#define CPM_INTERRUPT 11 /* = SIU_LEVEL5 (was: SIU_LEVEL2) */ + +/* We don't use the 8259. +*/ +#define NR_8259_INTS 0 + +#endif /* __MACH_PCU_E_H */ diff --git a/arch/ppc/platforms/pmac_backlight.c b/arch/ppc/platforms/pmac_backlight.c new file mode 100644 index 00000000000..ed2b1cebc19 --- /dev/null +++ b/arch/ppc/platforms/pmac_backlight.c @@ -0,0 +1,202 @@ +/* + * Miscellaneous procedures for dealing with the PowerMac hardware. + * Contains support for the backlight. + * + * Copyright (C) 2000 Benjamin Herrenschmidt + * + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/stddef.h> +#include <linux/reboot.h> +#include <linux/nvram.h> +#include <linux/console.h> +#include <asm/sections.h> +#include <asm/ptrace.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/system.h> +#include <asm/prom.h> +#include <asm/machdep.h> +#include <asm/nvram.h> +#include <asm/backlight.h> + +#include <linux/adb.h> +#include <linux/pmu.h> + +static struct backlight_controller *backlighter; +static void* backlighter_data; +static int backlight_autosave; +static int backlight_level = BACKLIGHT_MAX; +static int backlight_enabled = 1; +static int backlight_req_level = -1; +static int backlight_req_enable = -1; + +static void backlight_callback(void *); +static DECLARE_WORK(backlight_work, backlight_callback, NULL); + +void __pmac register_backlight_controller(struct backlight_controller *ctrler, + void *data, char *type) +{ + struct device_node* bk_node; + char *prop; + int valid = 0; + + /* There's already a matching controller, bail out */ + if (backlighter != NULL) + return; + + bk_node = find_devices("backlight"); + +#ifdef CONFIG_ADB_PMU + /* Special case for the old PowerBook since I can't test on it */ + backlight_autosave = machine_is_compatible("AAPL,3400/2400") + || machine_is_compatible("AAPL,3500"); + if ((backlight_autosave + || machine_is_compatible("AAPL,PowerBook1998") + || machine_is_compatible("PowerBook1,1")) + && !strcmp(type, "pmu")) + valid = 1; +#endif + if (bk_node) { + prop = get_property(bk_node, "backlight-control", NULL); + if (prop && !strncmp(prop, type, strlen(type))) + valid = 1; + } + if (!valid) + return; + backlighter = ctrler; + backlighter_data = data; + + if (bk_node && !backlight_autosave) + prop = get_property(bk_node, "bklt", NULL); + else + prop = NULL; + if (prop) { + backlight_level = ((*prop)+1) >> 1; + if (backlight_level > BACKLIGHT_MAX) + backlight_level = BACKLIGHT_MAX; + } + +#ifdef CONFIG_ADB_PMU + if (backlight_autosave) { + struct adb_request req; + pmu_request(&req, NULL, 2, 0xd9, 0); + while (!req.complete) + pmu_poll(); + backlight_level = req.reply[0] >> 4; + } +#endif + acquire_console_sem(); + if (!backlighter->set_enable(1, backlight_level, data)) + backlight_enabled = 1; + release_console_sem(); + + printk(KERN_INFO "Registered \"%s\" backlight controller," + "level: %d/15\n", type, backlight_level); +} +EXPORT_SYMBOL(register_backlight_controller); + +void __pmac unregister_backlight_controller(struct backlight_controller + *ctrler, void *data) +{ + /* We keep the current backlight level (for now) */ + if (ctrler == backlighter && data == backlighter_data) + backlighter = NULL; +} +EXPORT_SYMBOL(unregister_backlight_controller); + +static int __pmac __set_backlight_enable(int enable) +{ + int rc; + + if (!backlighter) + return -ENODEV; + acquire_console_sem(); + rc = backlighter->set_enable(enable, backlight_level, + backlighter_data); + if (!rc) + backlight_enabled = enable; + release_console_sem(); + return rc; +} +int __pmac set_backlight_enable(int enable) +{ + if (!backlighter) + return -ENODEV; + backlight_req_enable = enable; + schedule_work(&backlight_work); + return 0; +} + +EXPORT_SYMBOL(set_backlight_enable); + +int __pmac get_backlight_enable(void) +{ + if (!backlighter) + return -ENODEV; + return backlight_enabled; +} +EXPORT_SYMBOL(get_backlight_enable); + +static int __pmac __set_backlight_level(int level) +{ + int rc = 0; + + if (!backlighter) + return -ENODEV; + if (level < BACKLIGHT_MIN) + level = BACKLIGHT_OFF; + if (level > BACKLIGHT_MAX) + level = BACKLIGHT_MAX; + acquire_console_sem(); + if (backlight_enabled) + rc = backlighter->set_level(level, backlighter_data); + if (!rc) + backlight_level = level; + release_console_sem(); + if (!rc && !backlight_autosave) { + level <<=1; + if (level & 0x10) + level |= 0x01; + // -- todo: save to property "bklt" + } + return rc; +} +int __pmac set_backlight_level(int level) +{ + if (!backlighter) + return -ENODEV; + backlight_req_level = level; + schedule_work(&backlight_work); + return 0; +} + +EXPORT_SYMBOL(set_backlight_level); + +int __pmac get_backlight_level(void) +{ + if (!backlighter) + return -ENODEV; + return backlight_level; +} +EXPORT_SYMBOL(get_backlight_level); + +static void backlight_callback(void *dummy) +{ + int level, enable; + + do { + level = backlight_req_level; + enable = backlight_req_enable; + mb(); + + if (level >= 0) + __set_backlight_level(level); + if (enable >= 0) + __set_backlight_enable(enable); + } while(cmpxchg(&backlight_req_level, level, -1) != level || + cmpxchg(&backlight_req_enable, enable, -1) != enable); +} diff --git a/arch/ppc/platforms/pmac_cache.S b/arch/ppc/platforms/pmac_cache.S new file mode 100644 index 00000000000..c00e0352044 --- /dev/null +++ b/arch/ppc/platforms/pmac_cache.S @@ -0,0 +1,325 @@ +/* + * This file contains low-level cache management functions + * used for sleep and CPU speed changes on Apple machines. + * (In fact the only thing that is Apple-specific is that we assume + * that we can read from ROM at physical address 0xfff00000.) + * + * Copyright (C) 2004 Paul Mackerras (paulus@samba.org) and + * Benjamin Herrenschmidt (benh@kernel.crashing.org) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include <linux/config.h> +#include <asm/processor.h> +#include <asm/ppc_asm.h> +#include <asm/cputable.h> + +/* + * Flush and disable all data caches (dL1, L2, L3). This is used + * when going to sleep, when doing a PMU based cpufreq transition, + * or when "offlining" a CPU on SMP machines. This code is over + * paranoid, but I've had enough issues with various CPU revs and + * bugs that I decided it was worth beeing over cautious + */ + +_GLOBAL(flush_disable_caches) +BEGIN_FTR_SECTION + b flush_disable_745x +END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450) +BEGIN_FTR_SECTION + b flush_disable_75x +END_FTR_SECTION_IFSET(CPU_FTR_L2CR) + b __flush_disable_L1 + +/* This is the code for G3 and 74[01]0 */ +flush_disable_75x: + mflr r10 + + /* Turn off EE and DR in MSR */ + mfmsr r11 + rlwinm r0,r11,0,~MSR_EE + rlwinm r0,r0,0,~MSR_DR + sync + mtmsr r0 + isync + + /* Stop DST streams */ +BEGIN_FTR_SECTION + DSSALL + sync +END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) + + /* Stop DPM */ + mfspr r8,SPRN_HID0 /* Save SPRN_HID0 in r8 */ + rlwinm r4,r8,0,12,10 /* Turn off HID0[DPM] */ + sync + mtspr SPRN_HID0,r4 /* Disable DPM */ + sync + + /* disp-flush L1 */ + li r4,0x4000 + mtctr r4 + lis r4,0xfff0 +1: lwzx r0,r0,r4 + addi r4,r4,32 + bdnz 1b + sync + isync + + /* disable / invalidate / enable L1 data */ + mfspr r3,SPRN_HID0 + rlwinm r0,r0,0,~HID0_DCE + mtspr SPRN_HID0,r3 + sync + isync + ori r3,r3,HID0_DCE|HID0_DCI + sync + isync + mtspr SPRN_HID0,r3 + xori r3,r3,HID0_DCI + mtspr SPRN_HID0,r3 + sync + + /* Get the current enable bit of the L2CR into r4 */ + mfspr r5,SPRN_L2CR + /* Set to data-only (pre-745x bit) */ + oris r3,r5,L2CR_L2DO@h + b 2f + /* When disabling L2, code must be in L1 */ + .balign 32 +1: mtspr SPRN_L2CR,r3 +3: sync + isync + b 1f +2: b 3f +3: sync + isync + b 1b +1: /* disp-flush L2. The interesting thing here is that the L2 can be + * up to 2Mb ... so using the ROM, we'll end up wrapping back to memory + * but that is probbaly fine. We disp-flush over 4Mb to be safe + */ + lis r4,2 + mtctr r4 + lis r4,0xfff0 +1: lwzx r0,r0,r4 + addi r4,r4,32 + bdnz 1b + sync + isync + /* now disable L2 */ + rlwinm r5,r5,0,~L2CR_L2E + b 2f + /* When disabling L2, code must be in L1 */ + .balign 32 +1: mtspr SPRN_L2CR,r5 +3: sync + isync + b 1f +2: b 3f +3: sync + isync + b 1b +1: sync + isync + /* Invalidate L2. This is pre-745x, we clear the L2I bit ourselves */ + oris r4,r5,L2CR_L2I@h + mtspr SPRN_L2CR,r4 + sync + isync + xoris r4,r4,L2CR_L2I@h + sync + mtspr SPRN_L2CR,r4 + sync + + /* now disable the L1 data cache */ + mfspr r0,SPRN_HID0 + rlwinm r0,r0,0,~HID0_DCE + mtspr SPRN_HID0,r0 + sync + isync + + /* Restore HID0[DPM] to whatever it was before */ + sync + mtspr SPRN_HID0,r8 + sync + + /* restore DR and EE */ + sync + mtmsr r11 + isync + + mtlr r10 + blr + +/* This code is for 745x processors */ +flush_disable_745x: + /* Turn off EE and DR in MSR */ + mfmsr r11 + rlwinm r0,r11,0,~MSR_EE + rlwinm r0,r0,0,~MSR_DR + sync + mtmsr r0 + isync + + /* Stop prefetch streams */ + DSSALL + sync + + /* Disable L2 prefetching */ + mfspr r0,SPRN_MSSCR0 + rlwinm r0,r0,0,0,29 + mtspr SPRN_MSSCR0,r0 + sync + isync + lis r4,0 + dcbf 0,r4 + dcbf 0,r4 + dcbf 0,r4 + dcbf 0,r4 + dcbf 0,r4 + dcbf 0,r4 + dcbf 0,r4 + dcbf 0,r4 + + /* Due to a bug with the HW flush on some CPU revs, we occasionally + * experience data corruption. I'm adding a displacement flush along + * with a dcbf loop over a few Mb to "help". The problem isn't totally + * fixed by this in theory, but at least, in practice, I couldn't reproduce + * it even with a big hammer... + */ + + lis r4,0x0002 + mtctr r4 + li r4,0 +1: + lwzx r0,r0,r4 + addi r4,r4,32 /* Go to start of next cache line */ + bdnz 1b + isync + + /* Now, flush the first 4MB of memory */ + lis r4,0x0002 + mtctr r4 + li r4,0 + sync +1: + dcbf 0,r4 + addi r4,r4,32 /* Go to start of next cache line */ + bdnz 1b + + /* Flush and disable the L1 data cache */ + mfspr r6,SPRN_LDSTCR + lis r3,0xfff0 /* read from ROM for displacement flush */ + li r4,0xfe /* start with only way 0 unlocked */ + li r5,128 /* 128 lines in each way */ +1: mtctr r5 + rlwimi r6,r4,0,24,31 + mtspr SPRN_LDSTCR,r6 + sync + isync +2: lwz r0,0(r3) /* touch each cache line */ + addi r3,r3,32 + bdnz 2b + rlwinm r4,r4,1,24,30 /* move on to the next way */ + ori r4,r4,1 + cmpwi r4,0xff /* all done? */ + bne 1b + /* now unlock the L1 data cache */ + li r4,0 + rlwimi r6,r4,0,24,31 + sync + mtspr SPRN_LDSTCR,r6 + sync + isync + + /* Flush the L2 cache using the hardware assist */ + mfspr r3,SPRN_L2CR + cmpwi r3,0 /* check if it is enabled first */ + bge 4f + oris r0,r3,(L2CR_L2IO_745x|L2CR_L2DO_745x)@h + b 2f + /* When disabling/locking L2, code must be in L1 */ + .balign 32 +1: mtspr SPRN_L2CR,r0 /* lock the L2 cache */ +3: sync + isync + b 1f +2: b 3f +3: sync + isync + b 1b +1: sync + isync + ori r0,r3,L2CR_L2HWF_745x + sync + mtspr SPRN_L2CR,r0 /* set the hardware flush bit */ +3: mfspr r0,SPRN_L2CR /* wait for it to go to 0 */ + andi. r0,r0,L2CR_L2HWF_745x + bne 3b + sync + rlwinm r3,r3,0,~L2CR_L2E + b 2f + /* When disabling L2, code must be in L1 */ + .balign 32 +1: mtspr SPRN_L2CR,r3 /* disable the L2 cache */ +3: sync + isync + b 1f +2: b 3f +3: sync + isync + b 1b +1: sync + isync + oris r4,r3,L2CR_L2I@h + mtspr SPRN_L2CR,r4 + sync + isync +1: mfspr r4,SPRN_L2CR + andis. r0,r4,L2CR_L2I@h + bne 1b + sync + +BEGIN_FTR_SECTION + /* Flush the L3 cache using the hardware assist */ +4: mfspr r3,SPRN_L3CR + cmpwi r3,0 /* check if it is enabled */ + bge 6f + oris r0,r3,L3CR_L3IO@h + ori r0,r0,L3CR_L3DO + sync + mtspr SPRN_L3CR,r0 /* lock the L3 cache */ + sync + isync + ori r0,r0,L3CR_L3HWF + sync + mtspr SPRN_L3CR,r0 /* set the hardware flush bit */ +5: mfspr r0,SPRN_L3CR /* wait for it to go to zero */ + andi. r0,r0,L3CR_L3HWF + bne 5b + rlwinm r3,r3,0,~L3CR_L3E + sync + mtspr SPRN_L3CR,r3 /* disable the L3 cache */ + sync + ori r4,r3,L3CR_L3I + mtspr SPRN_L3CR,r4 +1: mfspr r4,SPRN_L3CR + andi. r0,r4,L3CR_L3I + bne 1b + sync +END_FTR_SECTION_IFSET(CPU_FTR_L3CR) + +6: mfspr r0,SPRN_HID0 /* now disable the L1 data cache */ + rlwinm r0,r0,0,~HID0_DCE + mtspr SPRN_HID0,r0 + sync + isync + mtmsr r11 /* restore DR and EE */ + isync + blr diff --git a/arch/ppc/platforms/pmac_cpufreq.c b/arch/ppc/platforms/pmac_cpufreq.c new file mode 100644 index 00000000000..9c85f9ca1cf --- /dev/null +++ b/arch/ppc/platforms/pmac_cpufreq.c @@ -0,0 +1,571 @@ +/* + * arch/ppc/platforms/pmac_cpufreq.c + * + * Copyright (C) 2002 - 2004 Benjamin Herrenschmidt <benh@kernel.crashing.org> + * Copyright (C) 2004 John Steele Scott <toojays@toojays.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/sched.h> +#include <linux/adb.h> +#include <linux/pmu.h> +#include <linux/slab.h> +#include <linux/cpufreq.h> +#include <linux/init.h> +#include <linux/sysdev.h> +#include <linux/i2c.h> +#include <linux/hardirq.h> +#include <asm/prom.h> +#include <asm/machdep.h> +#include <asm/irq.h> +#include <asm/pmac_feature.h> +#include <asm/mmu_context.h> +#include <asm/sections.h> +#include <asm/cputable.h> +#include <asm/time.h> +#include <asm/system.h> +#include <asm/open_pic.h> + +/* WARNING !!! This will cause calibrate_delay() to be called, + * but this is an __init function ! So you MUST go edit + * init/main.c to make it non-init before enabling DEBUG_FREQ + */ +#undef DEBUG_FREQ + +/* + * There is a problem with the core cpufreq code on SMP kernels, + * it won't recalculate the Bogomips properly + */ +#ifdef CONFIG_SMP +#warning "WARNING, CPUFREQ not recommended on SMP kernels" +#endif + +extern void low_choose_7447a_dfs(int dfs); +extern void low_choose_750fx_pll(int pll); +extern void low_sleep_handler(void); + +/* + * Currently, PowerMac cpufreq supports only high & low frequencies + * that are set by the firmware + */ +static unsigned int low_freq; +static unsigned int hi_freq; +static unsigned int cur_freq; + +/* + * Different models uses different mecanisms to switch the frequency + */ +static int (*set_speed_proc)(int low_speed); + +/* + * Some definitions used by the various speedprocs + */ +static u32 voltage_gpio; +static u32 frequency_gpio; +static u32 slew_done_gpio; + + +#define PMAC_CPU_LOW_SPEED 1 +#define PMAC_CPU_HIGH_SPEED 0 + +/* There are only two frequency states for each processor. Values + * are in kHz for the time being. + */ +#define CPUFREQ_HIGH PMAC_CPU_HIGH_SPEED +#define CPUFREQ_LOW PMAC_CPU_LOW_SPEED + +static struct cpufreq_frequency_table pmac_cpu_freqs[] = { + {CPUFREQ_HIGH, 0}, + {CPUFREQ_LOW, 0}, + {0, CPUFREQ_TABLE_END}, +}; + +static inline void wakeup_decrementer(void) +{ + set_dec(tb_ticks_per_jiffy); + /* No currently-supported powerbook has a 601, + * so use get_tbl, not native + */ + last_jiffy_stamp(0) = tb_last_stamp = get_tbl(); +} + +#ifdef DEBUG_FREQ +static inline void debug_calc_bogomips(void) +{ + /* This will cause a recalc of bogomips and display the + * result. We backup/restore the value to avoid affecting the + * core cpufreq framework's own calculation. + */ + extern void calibrate_delay(void); + + unsigned long save_lpj = loops_per_jiffy; + calibrate_delay(); + loops_per_jiffy = save_lpj; +} +#endif /* DEBUG_FREQ */ + +/* Switch CPU speed under 750FX CPU control + */ +static int __pmac cpu_750fx_cpu_speed(int low_speed) +{ +#ifdef DEBUG_FREQ + printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1)); +#endif +#ifdef CONFIG_6xx + low_choose_750fx_pll(low_speed); +#endif +#ifdef DEBUG_FREQ + printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1)); + debug_calc_bogomips(); +#endif + + return 0; +} + +/* Switch CPU speed using DFS */ +static int __pmac dfs_set_cpu_speed(int low_speed) +{ + if (low_speed == 0) { + /* ramping up, set voltage first */ + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05); + /* Make sure we sleep for at least 1ms */ + msleep(1); + } + + /* set frequency */ + low_choose_7447a_dfs(low_speed); + + if (low_speed == 1) { + /* ramping down, set voltage last */ + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04); + msleep(1); + } + + return 0; +} + +static unsigned int __pmac dfs_get_cpu_speed(unsigned int cpu) +{ + if (mfspr(SPRN_HID1) & HID1_DFS) + return low_freq; + else + return hi_freq; +} + + +/* Switch CPU speed using slewing GPIOs + */ +static int __pmac gpios_set_cpu_speed(int low_speed) +{ + int gpio; + + /* If ramping up, set voltage first */ + if (low_speed == 0) { + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05); + /* Delay is way too big but it's ok, we schedule */ + msleep(10); + } + + /* Set frequency */ + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, frequency_gpio, + low_speed ? 0x04 : 0x05); + udelay(200); + do { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + gpio = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, slew_done_gpio, 0); + } while((gpio & 0x02) == 0); + + /* If ramping down, set voltage last */ + if (low_speed == 1) { + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04); + /* Delay is way too big but it's ok, we schedule */ + msleep(10); + } + +#ifdef DEBUG_FREQ + debug_calc_bogomips(); +#endif + + return 0; +} + +/* Switch CPU speed under PMU control + */ +static int __pmac pmu_set_cpu_speed(int low_speed) +{ + struct adb_request req; + unsigned long save_l2cr; + unsigned long save_l3cr; + + preempt_disable(); + +#ifdef DEBUG_FREQ + printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1)); +#endif + /* Disable all interrupt sources on openpic */ + openpic_set_priority(0xf); + + /* Make sure the decrementer won't interrupt us */ + asm volatile("mtdec %0" : : "r" (0x7fffffff)); + /* Make sure any pending DEC interrupt occuring while we did + * the above didn't re-enable the DEC */ + mb(); + asm volatile("mtdec %0" : : "r" (0x7fffffff)); + + /* We can now disable MSR_EE */ + local_irq_disable(); + + /* Giveup the FPU & vec */ + enable_kernel_fp(); + +#ifdef CONFIG_ALTIVEC + if (cpu_has_feature(CPU_FTR_ALTIVEC)) + enable_kernel_altivec(); +#endif /* CONFIG_ALTIVEC */ + + /* Save & disable L2 and L3 caches */ + save_l3cr = _get_L3CR(); /* (returns -1 if not available) */ + save_l2cr = _get_L2CR(); /* (returns -1 if not available) */ + + /* Send the new speed command. My assumption is that this command + * will cause PLL_CFG[0..3] to be changed next time CPU goes to sleep + */ + pmu_request(&req, NULL, 6, PMU_CPU_SPEED, 'W', 'O', 'O', 'F', low_speed); + while (!req.complete) + pmu_poll(); + + /* Prepare the northbridge for the speed transition */ + pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,1,1); + + /* Call low level code to backup CPU state and recover from + * hardware reset + */ + low_sleep_handler(); + + /* Restore the northbridge */ + pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,1,0); + + /* Restore L2 cache */ + if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0) + _set_L2CR(save_l2cr); + /* Restore L3 cache */ + if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0) + _set_L3CR(save_l3cr); + + /* Restore userland MMU context */ + set_context(current->active_mm->context, current->active_mm->pgd); + +#ifdef DEBUG_FREQ + printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1)); +#endif + + /* Restore low level PMU operations */ + pmu_unlock(); + + /* Restore decrementer */ + wakeup_decrementer(); + + /* Restore interrupts */ + openpic_set_priority(0); + + /* Let interrupts flow again ... */ + local_irq_enable(); + +#ifdef DEBUG_FREQ + debug_calc_bogomips(); +#endif + + preempt_enable(); + + return 0; +} + +static int __pmac do_set_cpu_speed(int speed_mode) +{ + struct cpufreq_freqs freqs; + + freqs.old = cur_freq; + freqs.new = (speed_mode == PMAC_CPU_HIGH_SPEED) ? hi_freq : low_freq; + freqs.cpu = smp_processor_id(); + + if (freqs.old == freqs.new) + return 0; + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + set_speed_proc(speed_mode == PMAC_CPU_LOW_SPEED); + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + cur_freq = (speed_mode == PMAC_CPU_HIGH_SPEED) ? hi_freq : low_freq; + + return 0; +} + +static int __pmac pmac_cpufreq_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, pmac_cpu_freqs); +} + +static int __pmac pmac_cpufreq_target( struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int newstate = 0; + + if (cpufreq_frequency_table_target(policy, pmac_cpu_freqs, + target_freq, relation, &newstate)) + return -EINVAL; + + return do_set_cpu_speed(newstate); +} + +unsigned int __pmac pmac_get_one_cpufreq(int i) +{ + /* Supports only one CPU for now */ + return (i == 0) ? cur_freq : 0; +} + +static int __pmac pmac_cpufreq_cpu_init(struct cpufreq_policy *policy) +{ + if (policy->cpu != 0) + return -ENODEV; + + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; + policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + policy->cur = cur_freq; + + return cpufreq_frequency_table_cpuinfo(policy, &pmac_cpu_freqs[0]); +} + +static u32 __pmac read_gpio(struct device_node *np) +{ + u32 *reg = (u32 *)get_property(np, "reg", NULL); + + if (reg == NULL) + return 0; + /* That works for all keylargos but shall be fixed properly + * some day... + */ + return 0x50 + (*reg); +} + +static struct cpufreq_driver pmac_cpufreq_driver = { + .verify = pmac_cpufreq_verify, + .target = pmac_cpufreq_target, + .init = pmac_cpufreq_cpu_init, + .name = "powermac", + .owner = THIS_MODULE, +}; + + +static int __pmac pmac_cpufreq_init_MacRISC3(struct device_node *cpunode) +{ + struct device_node *volt_gpio_np = of_find_node_by_name(NULL, + "voltage-gpio"); + struct device_node *freq_gpio_np = of_find_node_by_name(NULL, + "frequency-gpio"); + struct device_node *slew_done_gpio_np = of_find_node_by_name(NULL, + "slewing-done"); + u32 *value; + + /* + * Check to see if it's GPIO driven or PMU only + * + * The way we extract the GPIO address is slightly hackish, but it + * works well enough for now. We need to abstract the whole GPIO + * stuff sooner or later anyway + */ + + if (volt_gpio_np) + voltage_gpio = read_gpio(volt_gpio_np); + if (freq_gpio_np) + frequency_gpio = read_gpio(freq_gpio_np); + if (slew_done_gpio_np) + slew_done_gpio = read_gpio(slew_done_gpio_np); + + /* If we use the frequency GPIOs, calculate the min/max speeds based + * on the bus frequencies + */ + if (frequency_gpio && slew_done_gpio) { + int lenp, rc; + u32 *freqs, *ratio; + + freqs = (u32 *)get_property(cpunode, "bus-frequencies", &lenp); + lenp /= sizeof(u32); + if (freqs == NULL || lenp != 2) { + printk(KERN_ERR "cpufreq: bus-frequencies incorrect or missing\n"); + return 1; + } + ratio = (u32 *)get_property(cpunode, "processor-to-bus-ratio*2", NULL); + if (ratio == NULL) { + printk(KERN_ERR "cpufreq: processor-to-bus-ratio*2 missing\n"); + return 1; + } + + /* Get the min/max bus frequencies */ + low_freq = min(freqs[0], freqs[1]); + hi_freq = max(freqs[0], freqs[1]); + + /* Grrrr.. It _seems_ that the device-tree is lying on the low bus + * frequency, it claims it to be around 84Mhz on some models while + * it appears to be approx. 101Mhz on all. Let's hack around here... + * fortunately, we don't need to be too precise + */ + if (low_freq < 98000000) + low_freq = 101000000; + + /* Convert those to CPU core clocks */ + low_freq = (low_freq * (*ratio)) / 2000; + hi_freq = (hi_freq * (*ratio)) / 2000; + + /* Now we get the frequencies, we read the GPIO to see what is out current + * speed + */ + rc = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, frequency_gpio, 0); + cur_freq = (rc & 0x01) ? hi_freq : low_freq; + + set_speed_proc = gpios_set_cpu_speed; + return 1; + } + + /* If we use the PMU, look for the min & max frequencies in the + * device-tree + */ + value = (u32 *)get_property(cpunode, "min-clock-frequency", NULL); + if (!value) + return 1; + low_freq = (*value) / 1000; + /* The PowerBook G4 12" (PowerBook6,1) has an error in the device-tree + * here */ + if (low_freq < 100000) + low_freq *= 10; + + value = (u32 *)get_property(cpunode, "max-clock-frequency", NULL); + if (!value) + return 1; + hi_freq = (*value) / 1000; + set_speed_proc = pmu_set_cpu_speed; + + return 0; +} + +static int __pmac pmac_cpufreq_init_7447A(struct device_node *cpunode) +{ + struct device_node *volt_gpio_np; + u32 *reg; + struct cpufreq_driver *driver = &pmac_cpufreq_driver; + + /* Look for voltage GPIO */ + volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select"); + reg = (u32 *)get_property(volt_gpio_np, "reg", NULL); + voltage_gpio = *reg; + if (!volt_gpio_np){ + printk(KERN_ERR "cpufreq: missing cpu-vcore-select gpio\n"); + return 1; + } + + /* OF only reports the high frequency */ + hi_freq = cur_freq; + low_freq = cur_freq/2; + + /* Read actual frequency from CPU */ + driver->get = dfs_get_cpu_speed; + cur_freq = driver->get(0); + set_speed_proc = dfs_set_cpu_speed; + + return 0; +} + +/* Currently, we support the following machines: + * + * - Titanium PowerBook 1Ghz (PMU based, 667Mhz & 1Ghz) + * - Titanium PowerBook 800 (PMU based, 667Mhz & 800Mhz) + * - Titanium PowerBook 400 (PMU based, 300Mhz & 400Mhz) + * - Titanium PowerBook 500 (PMU based, 300Mhz & 500Mhz) + * - iBook2 500/600 (PMU based, 400Mhz & 500/600Mhz) + * - iBook2 700 (CPU based, 400Mhz & 700Mhz, support low voltage) + * - Recent MacRISC3 laptops + * - All new machines with 7447A CPUs + */ +static int __init pmac_cpufreq_setup(void) +{ + struct device_node *cpunode; + u32 *value; + + if (strstr(cmd_line, "nocpufreq")) + return 0; + + /* Assume only one CPU */ + cpunode = find_type_devices("cpu"); + if (!cpunode) + goto out; + + /* Get current cpu clock freq */ + value = (u32 *)get_property(cpunode, "clock-frequency", NULL); + if (!value) + goto out; + cur_freq = (*value) / 1000; + + /* Check for 7447A based MacRISC3 */ + if (machine_is_compatible("MacRISC3") && + get_property(cpunode, "dynamic-power-step", NULL) && + PVR_VER(mfspr(SPRN_PVR)) == 0x8003) { + pmac_cpufreq_init_7447A(cpunode); + /* Check for other MacRISC3 machines */ + } else if (machine_is_compatible("PowerBook3,4") || + machine_is_compatible("PowerBook3,5") || + machine_is_compatible("MacRISC3")) { + pmac_cpufreq_init_MacRISC3(cpunode); + /* Else check for iBook2 500/600 */ + } else if (machine_is_compatible("PowerBook4,1")) { + hi_freq = cur_freq; + low_freq = 400000; + set_speed_proc = pmu_set_cpu_speed; + } + /* Else check for TiPb 400 & 500 */ + else if (machine_is_compatible("PowerBook3,2")) { + /* We only know about the 400 MHz and the 500Mhz model + * they both have 300 MHz as low frequency + */ + if (cur_freq < 350000 || cur_freq > 550000) + goto out; + hi_freq = cur_freq; + low_freq = 300000; + set_speed_proc = pmu_set_cpu_speed; + } + /* Else check for 750FX */ + else if (PVR_VER(mfspr(SPRN_PVR)) == 0x7000) { + if (get_property(cpunode, "dynamic-power-step", NULL) == NULL) + goto out; + hi_freq = cur_freq; + value = (u32 *)get_property(cpunode, "reduced-clock-frequency", NULL); + if (!value) + goto out; + low_freq = (*value) / 1000; + set_speed_proc = cpu_750fx_cpu_speed; + } +out: + if (set_speed_proc == NULL) + return -ENODEV; + + pmac_cpu_freqs[CPUFREQ_LOW].frequency = low_freq; + pmac_cpu_freqs[CPUFREQ_HIGH].frequency = hi_freq; + + printk(KERN_INFO "Registering PowerMac CPU frequency driver\n"); + printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Boot: %d Mhz\n", + low_freq/1000, hi_freq/1000, cur_freq/1000); + + return cpufreq_register_driver(&pmac_cpufreq_driver); +} + +module_init(pmac_cpufreq_setup); + diff --git a/arch/ppc/platforms/pmac_feature.c b/arch/ppc/platforms/pmac_feature.c new file mode 100644 index 00000000000..8e60550863a --- /dev/null +++ b/arch/ppc/platforms/pmac_feature.c @@ -0,0 +1,2972 @@ +/* + * arch/ppc/platforms/pmac_feature.c + * + * Copyright (C) 1996-2001 Paul Mackerras (paulus@cs.anu.edu.au) + * Ben. Herrenschmidt (benh@kernel.crashing.org) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * TODO: + * + * - Replace mdelay with some schedule loop if possible + * - Shorten some obfuscated delays on some routines (like modem + * power) + * - Refcount some clocks (see darwin) + * - Split split split... + * + */ +#include <linux/config.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/spinlock.h> +#include <linux/adb.h> +#include <linux/pmu.h> +#include <linux/ioport.h> +#include <linux/pci.h> +#include <asm/sections.h> +#include <asm/errno.h> +#include <asm/ohare.h> +#include <asm/heathrow.h> +#include <asm/keylargo.h> +#include <asm/uninorth.h> +#include <asm/io.h> +#include <asm/prom.h> +#include <asm/machdep.h> +#include <asm/pmac_feature.h> +#include <asm/dbdma.h> +#include <asm/pci-bridge.h> +#include <asm/pmac_low_i2c.h> + +#undef DEBUG_FEATURE + +#ifdef DEBUG_FEATURE +#define DBG(fmt,...) printk(KERN_DEBUG fmt) +#else +#define DBG(fmt,...) +#endif + +#ifdef CONFIG_6xx +extern int powersave_lowspeed; +#endif + +extern int powersave_nap; +extern struct device_node *k2_skiplist[2]; + + +/* + * We use a single global lock to protect accesses. Each driver has + * to take care of its own locking + */ +static DEFINE_SPINLOCK(feature_lock __pmacdata); + +#define LOCK(flags) spin_lock_irqsave(&feature_lock, flags); +#define UNLOCK(flags) spin_unlock_irqrestore(&feature_lock, flags); + + +/* + * Instance of some macio stuffs + */ +struct macio_chip macio_chips[MAX_MACIO_CHIPS] __pmacdata; + +struct macio_chip* __pmac +macio_find(struct device_node* child, int type) +{ + while(child) { + int i; + + for (i=0; i < MAX_MACIO_CHIPS && macio_chips[i].of_node; i++) + if (child == macio_chips[i].of_node && + (!type || macio_chips[i].type == type)) + return &macio_chips[i]; + child = child->parent; + } + return NULL; +} + +static const char* macio_names[] __pmacdata = +{ + "Unknown", + "Grand Central", + "OHare", + "OHareII", + "Heathrow", + "Gatwick", + "Paddington", + "Keylargo", + "Pangea", + "Intrepid", + "K2" +}; + + + +/* + * Uninorth reg. access. Note that Uni-N regs are big endian + */ + +#define UN_REG(r) (uninorth_base + ((r) >> 2)) +#define UN_IN(r) (in_be32(UN_REG(r))) +#define UN_OUT(r,v) (out_be32(UN_REG(r), (v))) +#define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v))) +#define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v))) + +static struct device_node* uninorth_node __pmacdata; +static u32 __iomem * uninorth_base __pmacdata; +static u32 uninorth_rev __pmacdata; +static int uninorth_u3 __pmacdata; +static void __iomem *u3_ht; + +/* + * For each motherboard family, we have a table of functions pointers + * that handle the various features. + */ + +typedef long (*feature_call)(struct device_node* node, long param, long value); + +struct feature_table_entry { + unsigned int selector; + feature_call function; +}; + +struct pmac_mb_def +{ + const char* model_string; + const char* model_name; + int model_id; + struct feature_table_entry* features; + unsigned long board_flags; +}; +static struct pmac_mb_def pmac_mb __pmacdata; + +/* + * Here are the chip specific feature functions + */ + +static inline int __pmac +simple_feature_tweak(struct device_node* node, int type, int reg, u32 mask, int value) +{ + struct macio_chip* macio; + unsigned long flags; + + macio = macio_find(node, type); + if (!macio) + return -ENODEV; + LOCK(flags); + if (value) + MACIO_BIS(reg, mask); + else + MACIO_BIC(reg, mask); + (void)MACIO_IN32(reg); + UNLOCK(flags); + + return 0; +} + +#ifndef CONFIG_POWER4 + +static long __pmac +ohare_htw_scc_enable(struct device_node* node, long param, long value) +{ + struct macio_chip* macio; + unsigned long chan_mask; + unsigned long fcr; + unsigned long flags; + int htw, trans; + unsigned long rmask; + + macio = macio_find(node, 0); + if (!macio) + return -ENODEV; + if (!strcmp(node->name, "ch-a")) + chan_mask = MACIO_FLAG_SCCA_ON; + else if (!strcmp(node->name, "ch-b")) + chan_mask = MACIO_FLAG_SCCB_ON; + else + return -ENODEV; + + htw = (macio->type == macio_heathrow || macio->type == macio_paddington + || macio->type == macio_gatwick); + /* On these machines, the HRW_SCC_TRANS_EN_N bit mustn't be touched */ + trans = (pmac_mb.model_id != PMAC_TYPE_YOSEMITE && + pmac_mb.model_id != PMAC_TYPE_YIKES); + if (value) { +#ifdef CONFIG_ADB_PMU + if ((param & 0xfff) == PMAC_SCC_IRDA) + pmu_enable_irled(1); +#endif /* CONFIG_ADB_PMU */ + LOCK(flags); + fcr = MACIO_IN32(OHARE_FCR); + /* Check if scc cell need enabling */ + if (!(fcr & OH_SCC_ENABLE)) { + fcr |= OH_SCC_ENABLE; + if (htw) { + /* Side effect: this will also power up the + * modem, but it's too messy to figure out on which + * ports this controls the tranceiver and on which + * it controls the modem + */ + if (trans) + fcr &= ~HRW_SCC_TRANS_EN_N; + MACIO_OUT32(OHARE_FCR, fcr); + fcr |= (rmask = HRW_RESET_SCC); + MACIO_OUT32(OHARE_FCR, fcr); + } else { + fcr |= (rmask = OH_SCC_RESET); + MACIO_OUT32(OHARE_FCR, fcr); + } + UNLOCK(flags); + (void)MACIO_IN32(OHARE_FCR); + mdelay(15); + LOCK(flags); + fcr &= ~rmask; + MACIO_OUT32(OHARE_FCR, fcr); + } + if (chan_mask & MACIO_FLAG_SCCA_ON) + fcr |= OH_SCCA_IO; + if (chan_mask & MACIO_FLAG_SCCB_ON) + fcr |= OH_SCCB_IO; + MACIO_OUT32(OHARE_FCR, fcr); + macio->flags |= chan_mask; + UNLOCK(flags); + if (param & PMAC_SCC_FLAG_XMON) + macio->flags |= MACIO_FLAG_SCC_LOCKED; + } else { + if (macio->flags & MACIO_FLAG_SCC_LOCKED) + return -EPERM; + LOCK(flags); + fcr = MACIO_IN32(OHARE_FCR); + if (chan_mask & MACIO_FLAG_SCCA_ON) + fcr &= ~OH_SCCA_IO; + if (chan_mask & MACIO_FLAG_SCCB_ON) + fcr &= ~OH_SCCB_IO; + MACIO_OUT32(OHARE_FCR, fcr); + if ((fcr & (OH_SCCA_IO | OH_SCCB_IO)) == 0) { + fcr &= ~OH_SCC_ENABLE; + if (htw && trans) + fcr |= HRW_SCC_TRANS_EN_N; + MACIO_OUT32(OHARE_FCR, fcr); + } + macio->flags &= ~(chan_mask); + UNLOCK(flags); + mdelay(10); +#ifdef CONFIG_ADB_PMU + if ((param & 0xfff) == PMAC_SCC_IRDA) + pmu_enable_irled(0); +#endif /* CONFIG_ADB_PMU */ + } + return 0; +} + +static long __pmac +ohare_floppy_enable(struct device_node* node, long param, long value) +{ + return simple_feature_tweak(node, macio_ohare, + OHARE_FCR, OH_FLOPPY_ENABLE, value); +} + +static long __pmac +ohare_mesh_enable(struct device_node* node, long param, long value) +{ + return simple_feature_tweak(node, macio_ohare, + OHARE_FCR, OH_MESH_ENABLE, value); +} + +static long __pmac +ohare_ide_enable(struct device_node* node, long param, long value) +{ + switch(param) { + case 0: + /* For some reason, setting the bit in set_initial_features() + * doesn't stick. I'm still investigating... --BenH. + */ + if (value) + simple_feature_tweak(node, macio_ohare, + OHARE_FCR, OH_IOBUS_ENABLE, 1); + return simple_feature_tweak(node, macio_ohare, + OHARE_FCR, OH_IDE0_ENABLE, value); + case 1: + return simple_feature_tweak(node, macio_ohare, + OHARE_FCR, OH_BAY_IDE_ENABLE, value); + default: + return -ENODEV; + } +} + +static long __pmac +ohare_ide_reset(struct device_node* node, long param, long value) +{ + switch(param) { + case 0: + return simple_feature_tweak(node, macio_ohare, + OHARE_FCR, OH_IDE0_RESET_N, !value); + case 1: + return simple_feature_tweak(node, macio_ohare, + OHARE_FCR, OH_IDE1_RESET_N, !value); + default: + return -ENODEV; + } +} + +static long __pmac +ohare_sleep_state(struct device_node* node, long param, long value) +{ + struct macio_chip* macio = &macio_chips[0]; + + if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0) + return -EPERM; + if (value == 1) { + MACIO_BIC(OHARE_FCR, OH_IOBUS_ENABLE); + } else if (value == 0) { + MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE); + } + + return 0; +} + +static long __pmac +heathrow_modem_enable(struct device_node* node, long param, long value) +{ + struct macio_chip* macio; + u8 gpio; + unsigned long flags; + + macio = macio_find(node, macio_unknown); + if (!macio) + return -ENODEV; + gpio = MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1; + if (!value) { + LOCK(flags); + MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio); + UNLOCK(flags); + (void)MACIO_IN8(HRW_GPIO_MODEM_RESET); + mdelay(250); + } + if (pmac_mb.model_id != PMAC_TYPE_YOSEMITE && + pmac_mb.model_id != PMAC_TYPE_YIKES) { + LOCK(flags); + if (value) + MACIO_BIC(HEATHROW_FCR, HRW_SCC_TRANS_EN_N); + else + MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N); + UNLOCK(flags); + (void)MACIO_IN32(HEATHROW_FCR); + mdelay(250); + } + if (value) { + LOCK(flags); + MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1); + (void)MACIO_IN8(HRW_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); LOCK(flags); + MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio); + (void)MACIO_IN8(HRW_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); LOCK(flags); + MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1); + (void)MACIO_IN8(HRW_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); + } + return 0; +} + +static long __pmac +heathrow_floppy_enable(struct device_node* node, long param, long value) +{ + return simple_feature_tweak(node, macio_unknown, + HEATHROW_FCR, + HRW_SWIM_ENABLE|HRW_BAY_FLOPPY_ENABLE, + value); +} + +static long __pmac +heathrow_mesh_enable(struct device_node* node, long param, long value) +{ + struct macio_chip* macio; + unsigned long flags; + + macio = macio_find(node, macio_unknown); + if (!macio) + return -ENODEV; + LOCK(flags); + /* Set clear mesh cell enable */ + if (value) + MACIO_BIS(HEATHROW_FCR, HRW_MESH_ENABLE); + else + MACIO_BIC(HEATHROW_FCR, HRW_MESH_ENABLE); + (void)MACIO_IN32(HEATHROW_FCR); + udelay(10); + /* Set/Clear termination power */ + if (value) + MACIO_BIC(HEATHROW_MBCR, 0x04000000); + else + MACIO_BIS(HEATHROW_MBCR, 0x04000000); + (void)MACIO_IN32(HEATHROW_MBCR); + udelay(10); + UNLOCK(flags); + + return 0; +} + +static long __pmac +heathrow_ide_enable(struct device_node* node, long param, long value) +{ + switch(param) { + case 0: + return simple_feature_tweak(node, macio_unknown, + HEATHROW_FCR, HRW_IDE0_ENABLE, value); + case 1: + return simple_feature_tweak(node, macio_unknown, + HEATHROW_FCR, HRW_BAY_IDE_ENABLE, value); + default: + return -ENODEV; + } +} + +static long __pmac +heathrow_ide_reset(struct device_node* node, long param, long value) +{ + switch(param) { + case 0: + return simple_feature_tweak(node, macio_unknown, + HEATHROW_FCR, HRW_IDE0_RESET_N, !value); + case 1: + return simple_feature_tweak(node, macio_unknown, + HEATHROW_FCR, HRW_IDE1_RESET_N, !value); + default: + return -ENODEV; + } +} + +static long __pmac +heathrow_bmac_enable(struct device_node* node, long param, long value) +{ + struct macio_chip* macio; + unsigned long flags; + + macio = macio_find(node, 0); + if (!macio) + return -ENODEV; + if (value) { + LOCK(flags); + MACIO_BIS(HEATHROW_FCR, HRW_BMAC_IO_ENABLE); + MACIO_BIS(HEATHROW_FCR, HRW_BMAC_RESET); + UNLOCK(flags); + (void)MACIO_IN32(HEATHROW_FCR); + mdelay(10); + LOCK(flags); + MACIO_BIC(HEATHROW_FCR, HRW_BMAC_RESET); + UNLOCK(flags); + (void)MACIO_IN32(HEATHROW_FCR); + mdelay(10); + } else { + LOCK(flags); + MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE); + UNLOCK(flags); + } + return 0; +} + +static long __pmac +heathrow_sound_enable(struct device_node* node, long param, long value) +{ + struct macio_chip* macio; + unsigned long flags; + + /* B&W G3 and Yikes don't support that properly (the + * sound appear to never come back after beeing shut down). + */ + if (pmac_mb.model_id == PMAC_TYPE_YOSEMITE || + pmac_mb.model_id == PMAC_TYPE_YIKES) + return 0; + + macio = macio_find(node, 0); + if (!macio) + return -ENODEV; + if (value) { + LOCK(flags); + MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE); + MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N); + UNLOCK(flags); + (void)MACIO_IN32(HEATHROW_FCR); + } else { + LOCK(flags); + MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N); + MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE); + UNLOCK(flags); + } + return 0; +} + +static u32 save_fcr[6] __pmacdata; +static u32 save_mbcr __pmacdata; +static u32 save_gpio_levels[2] __pmacdata; +static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT] __pmacdata; +static u8 save_gpio_normal[KEYLARGO_GPIO_CNT] __pmacdata; +static u32 save_unin_clock_ctl __pmacdata; +static struct dbdma_regs save_dbdma[13] __pmacdata; +static struct dbdma_regs save_alt_dbdma[13] __pmacdata; + +static void __pmac +dbdma_save(struct macio_chip* macio, struct dbdma_regs* save) +{ + int i; + + /* Save state & config of DBDMA channels */ + for (i=0; i<13; i++) { + volatile struct dbdma_regs __iomem * chan = (void __iomem *) + (macio->base + ((0x8000+i*0x100)>>2)); + save[i].cmdptr_hi = in_le32(&chan->cmdptr_hi); + save[i].cmdptr = in_le32(&chan->cmdptr); + save[i].intr_sel = in_le32(&chan->intr_sel); + save[i].br_sel = in_le32(&chan->br_sel); + save[i].wait_sel = in_le32(&chan->wait_sel); + } +} + +static void __pmac +dbdma_restore(struct macio_chip* macio, struct dbdma_regs* save) +{ + int i; + + /* Save state & config of DBDMA channels */ + for (i=0; i<13; i++) { + volatile struct dbdma_regs __iomem * chan = (void __iomem *) + (macio->base + ((0x8000+i*0x100)>>2)); + out_le32(&chan->control, (ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN)<<16); + while (in_le32(&chan->status) & ACTIVE) + mb(); + out_le32(&chan->cmdptr_hi, save[i].cmdptr_hi); + out_le32(&chan->cmdptr, save[i].cmdptr); + out_le32(&chan->intr_sel, save[i].intr_sel); + out_le32(&chan->br_sel, save[i].br_sel); + out_le32(&chan->wait_sel, save[i].wait_sel); + } +} + +static void __pmac +heathrow_sleep(struct macio_chip* macio, int secondary) +{ + if (secondary) { + dbdma_save(macio, save_alt_dbdma); + save_fcr[2] = MACIO_IN32(0x38); + save_fcr[3] = MACIO_IN32(0x3c); + } else { + dbdma_save(macio, save_dbdma); + save_fcr[0] = MACIO_IN32(0x38); + save_fcr[1] = MACIO_IN32(0x3c); + save_mbcr = MACIO_IN32(0x34); + /* Make sure sound is shut down */ + MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N); + MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE); + /* This seems to be necessary as well or the fan + * keeps coming up and battery drains fast */ + MACIO_BIC(HEATHROW_FCR, HRW_IOBUS_ENABLE); + MACIO_BIC(HEATHROW_FCR, HRW_IDE0_RESET_N); + /* Make sure eth is down even if module or sleep + * won't work properly */ + MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE | HRW_BMAC_RESET); + } + /* Make sure modem is shut down */ + MACIO_OUT8(HRW_GPIO_MODEM_RESET, + MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1); + MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N); + MACIO_BIC(HEATHROW_FCR, OH_SCCA_IO|OH_SCCB_IO|HRW_SCC_ENABLE); + + /* Let things settle */ + (void)MACIO_IN32(HEATHROW_FCR); +} + +static void __pmac +heathrow_wakeup(struct macio_chip* macio, int secondary) +{ + if (secondary) { + MACIO_OUT32(0x38, save_fcr[2]); + (void)MACIO_IN32(0x38); + mdelay(1); + MACIO_OUT32(0x3c, save_fcr[3]); + (void)MACIO_IN32(0x38); + mdelay(10); + dbdma_restore(macio, save_alt_dbdma); + } else { + MACIO_OUT32(0x38, save_fcr[0] | HRW_IOBUS_ENABLE); + (void)MACIO_IN32(0x38); + mdelay(1); + MACIO_OUT32(0x3c, save_fcr[1]); + (void)MACIO_IN32(0x38); + mdelay(1); + MACIO_OUT32(0x34, save_mbcr); + (void)MACIO_IN32(0x38); + mdelay(10); + dbdma_restore(macio, save_dbdma); + } +} + +static long __pmac +heathrow_sleep_state(struct device_node* node, long param, long value) +{ + if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0) + return -EPERM; + if (value == 1) { + if (macio_chips[1].type == macio_gatwick) + heathrow_sleep(&macio_chips[0], 1); + heathrow_sleep(&macio_chips[0], 0); + } else if (value == 0) { + heathrow_wakeup(&macio_chips[0], 0); + if (macio_chips[1].type == macio_gatwick) + heathrow_wakeup(&macio_chips[0], 1); + } + return 0; +} + +static long __pmac +core99_scc_enable(struct device_node* node, long param, long value) +{ + struct macio_chip* macio; + unsigned long flags; + unsigned long chan_mask; + u32 fcr; + + macio = macio_find(node, 0); + if (!macio) + return -ENODEV; + if (!strcmp(node->name, "ch-a")) + chan_mask = MACIO_FLAG_SCCA_ON; + else if (!strcmp(node->name, "ch-b")) + chan_mask = MACIO_FLAG_SCCB_ON; + else + return -ENODEV; + + if (value) { + int need_reset_scc = 0; + int need_reset_irda = 0; + + LOCK(flags); + fcr = MACIO_IN32(KEYLARGO_FCR0); + /* Check if scc cell need enabling */ + if (!(fcr & KL0_SCC_CELL_ENABLE)) { + fcr |= KL0_SCC_CELL_ENABLE; + need_reset_scc = 1; + } + if (chan_mask & MACIO_FLAG_SCCA_ON) { + fcr |= KL0_SCCA_ENABLE; + /* Don't enable line drivers for I2S modem */ + if ((param & 0xfff) == PMAC_SCC_I2S1) + fcr &= ~KL0_SCC_A_INTF_ENABLE; + else + fcr |= KL0_SCC_A_INTF_ENABLE; + } + if (chan_mask & MACIO_FLAG_SCCB_ON) { + fcr |= KL0_SCCB_ENABLE; + /* Perform irda specific inits */ + if ((param & 0xfff) == PMAC_SCC_IRDA) { + fcr &= ~KL0_SCC_B_INTF_ENABLE; + fcr |= KL0_IRDA_ENABLE; + fcr |= KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE; + fcr |= KL0_IRDA_SOURCE1_SEL; + fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0); + fcr &= ~(KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND); + need_reset_irda = 1; + } else + fcr |= KL0_SCC_B_INTF_ENABLE; + } + MACIO_OUT32(KEYLARGO_FCR0, fcr); + macio->flags |= chan_mask; + if (need_reset_scc) { + MACIO_BIS(KEYLARGO_FCR0, KL0_SCC_RESET); + (void)MACIO_IN32(KEYLARGO_FCR0); + UNLOCK(flags); + mdelay(15); + LOCK(flags); + MACIO_BIC(KEYLARGO_FCR0, KL0_SCC_RESET); + } + if (need_reset_irda) { + MACIO_BIS(KEYLARGO_FCR0, KL0_IRDA_RESET); + (void)MACIO_IN32(KEYLARGO_FCR0); + UNLOCK(flags); + mdelay(15); + LOCK(flags); + MACIO_BIC(KEYLARGO_FCR0, KL0_IRDA_RESET); + } + UNLOCK(flags); + if (param & PMAC_SCC_FLAG_XMON) + macio->flags |= MACIO_FLAG_SCC_LOCKED; + } else { + if (macio->flags & MACIO_FLAG_SCC_LOCKED) + return -EPERM; + LOCK(flags); + fcr = MACIO_IN32(KEYLARGO_FCR0); + if (chan_mask & MACIO_FLAG_SCCA_ON) + fcr &= ~KL0_SCCA_ENABLE; + if (chan_mask & MACIO_FLAG_SCCB_ON) { + fcr &= ~KL0_SCCB_ENABLE; + /* Perform irda specific clears */ + if ((param & 0xfff) == PMAC_SCC_IRDA) { + fcr &= ~KL0_IRDA_ENABLE; + fcr &= ~(KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE); + fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0); + fcr &= ~(KL0_IRDA_SOURCE1_SEL|KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND); + } + } + MACIO_OUT32(KEYLARGO_FCR0, fcr); + if ((fcr & (KL0_SCCA_ENABLE | KL0_SCCB_ENABLE)) == 0) { + fcr &= ~KL0_SCC_CELL_ENABLE; + MACIO_OUT32(KEYLARGO_FCR0, fcr); + } + macio->flags &= ~(chan_mask); + UNLOCK(flags); + mdelay(10); + } + return 0; +} + +static long __pmac +core99_modem_enable(struct device_node* node, long param, long value) +{ + struct macio_chip* macio; + u8 gpio; + unsigned long flags; + + /* Hack for internal USB modem */ + if (node == NULL) { + if (macio_chips[0].type != macio_keylargo) + return -ENODEV; + node = macio_chips[0].of_node; + } + macio = macio_find(node, 0); + if (!macio) + return -ENODEV; + gpio = MACIO_IN8(KL_GPIO_MODEM_RESET); + gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE; + gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA; + + if (!value) { + LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio); + UNLOCK(flags); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + mdelay(250); + } + LOCK(flags); + if (value) { + MACIO_BIC(KEYLARGO_FCR2, KL2_ALT_DATA_OUT); + UNLOCK(flags); + (void)MACIO_IN32(KEYLARGO_FCR2); + mdelay(250); + } else { + MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT); + UNLOCK(flags); + } + if (value) { + LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); + } + return 0; +} + +static long __pmac +pangea_modem_enable(struct device_node* node, long param, long value) +{ + struct macio_chip* macio; + u8 gpio; + unsigned long flags; + + /* Hack for internal USB modem */ + if (node == NULL) { + if (macio_chips[0].type != macio_pangea && + macio_chips[0].type != macio_intrepid) + return -ENODEV; + node = macio_chips[0].of_node; + } + macio = macio_find(node, 0); + if (!macio) + return -ENODEV; + gpio = MACIO_IN8(KL_GPIO_MODEM_RESET); + gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE; + gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA; + + if (!value) { + LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio); + UNLOCK(flags); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + mdelay(250); + } + LOCK(flags); + if (value) { + MACIO_OUT8(KL_GPIO_MODEM_POWER, + KEYLARGO_GPIO_OUTPUT_ENABLE); + UNLOCK(flags); + (void)MACIO_IN32(KEYLARGO_FCR2); + mdelay(250); + } else { + MACIO_OUT8(KL_GPIO_MODEM_POWER, + KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA); + UNLOCK(flags); + } + if (value) { + LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); + } + return 0; +} + +static long __pmac +core99_ata100_enable(struct device_node* node, long value) +{ + unsigned long flags; + struct pci_dev *pdev = NULL; + u8 pbus, pid; + + if (uninorth_rev < 0x24) + return -ENODEV; + + LOCK(flags); + if (value) + UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_ATA100); + else + UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_ATA100); + (void)UN_IN(UNI_N_CLOCK_CNTL); + UNLOCK(flags); + udelay(20); + + if (value) { + if (pci_device_from_OF_node(node, &pbus, &pid) == 0) + pdev = pci_find_slot(pbus, pid); + if (pdev == NULL) + return 0; + pci_enable_device(pdev); + pci_set_master(pdev); + } + return 0; +} + +static long __pmac +core99_ide_enable(struct device_node* node, long param, long value) +{ + /* Bus ID 0 to 2 are KeyLargo based IDE, busID 3 is U2 + * based ata-100 + */ + switch(param) { + case 0: + return simple_feature_tweak(node, macio_unknown, + KEYLARGO_FCR1, KL1_EIDE0_ENABLE, value); + case 1: + return simple_feature_tweak(node, macio_unknown, + KEYLARGO_FCR1, KL1_EIDE1_ENABLE, value); + case 2: + return simple_feature_tweak(node, macio_unknown, + KEYLARGO_FCR1, KL1_UIDE_ENABLE, value); + case 3: + return core99_ata100_enable(node, value); + default: + return -ENODEV; + } +} + +static long __pmac +core99_ide_reset(struct device_node* node, long param, long value) +{ + switch(param) { + case 0: + return simple_feature_tweak(node, macio_unknown, + KEYLARGO_FCR1, KL1_EIDE0_RESET_N, !value); + case 1: + return simple_feature_tweak(node, macio_unknown, + KEYLARGO_FCR1, KL1_EIDE1_RESET_N, !value); + case 2: + return simple_feature_tweak(node, macio_unknown, + KEYLARGO_FCR1, KL1_UIDE_RESET_N, !value); + default: + return -ENODEV; + } +} + +static long __pmac +core99_gmac_enable(struct device_node* node, long param, long value) +{ + unsigned long flags; + + LOCK(flags); + if (value) + UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC); + else + UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC); + (void)UN_IN(UNI_N_CLOCK_CNTL); + UNLOCK(flags); + udelay(20); + + return 0; +} + +static long __pmac +core99_gmac_phy_reset(struct device_node* node, long param, long value) +{ + unsigned long flags; + struct macio_chip* macio; + + macio = &macio_chips[0]; + if (macio->type != macio_keylargo && macio->type != macio_pangea && + macio->type != macio_intrepid) + return -ENODEV; + + LOCK(flags); + MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, KEYLARGO_GPIO_OUTPUT_ENABLE); + (void)MACIO_IN8(KL_GPIO_ETH_PHY_RESET); + UNLOCK(flags); + mdelay(10); + LOCK(flags); + MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, /*KEYLARGO_GPIO_OUTPUT_ENABLE | */ + KEYLARGO_GPIO_OUTOUT_DATA); + UNLOCK(flags); + mdelay(10); + + return 0; +} + +static long __pmac +core99_sound_chip_enable(struct device_node* node, long param, long value) +{ + struct macio_chip* macio; + unsigned long flags; + + macio = macio_find(node, 0); + if (!macio) + return -ENODEV; + + /* Do a better probe code, screamer G4 desktops & + * iMacs can do that too, add a recalibrate in + * the driver as well + */ + if (pmac_mb.model_id == PMAC_TYPE_PISMO || + pmac_mb.model_id == PMAC_TYPE_TITANIUM) { + LOCK(flags); + if (value) + MACIO_OUT8(KL_GPIO_SOUND_POWER, + KEYLARGO_GPIO_OUTPUT_ENABLE | + KEYLARGO_GPIO_OUTOUT_DATA); + else + MACIO_OUT8(KL_GPIO_SOUND_POWER, + KEYLARGO_GPIO_OUTPUT_ENABLE); + (void)MACIO_IN8(KL_GPIO_SOUND_POWER); + UNLOCK(flags); + } + return 0; +} + +static long __pmac +core99_airport_enable(struct device_node* node, long param, long value) +{ + struct macio_chip* macio; + unsigned long flags; + int state; + + macio = macio_find(node, 0); + if (!macio) + return -ENODEV; + + /* Hint: we allow passing of macio itself for the sake of the + * sleep code + */ + if (node != macio->of_node && + (!node->parent || node->parent != macio->of_node)) + return -ENODEV; + state = (macio->flags & MACIO_FLAG_AIRPORT_ON) != 0; + if (value == state) + return 0; + if (value) { + /* This code is a reproduction of OF enable-cardslot + * and init-wireless methods, slightly hacked until + * I got it working. + */ + LOCK(flags); + MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 5); + (void)MACIO_IN8(KEYLARGO_GPIO_0+0xf); + UNLOCK(flags); + mdelay(10); + LOCK(flags); + MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 4); + (void)MACIO_IN8(KEYLARGO_GPIO_0+0xf); + UNLOCK(flags); + + mdelay(10); + + LOCK(flags); + MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16); + (void)MACIO_IN32(KEYLARGO_FCR2); + udelay(10); + MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xb, 0); + (void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xb); + udelay(10); + MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xa, 0x28); + (void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xa); + udelay(10); + MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xd, 0x28); + (void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xd); + udelay(10); + MACIO_OUT8(KEYLARGO_GPIO_0+0xd, 0x28); + (void)MACIO_IN8(KEYLARGO_GPIO_0+0xd); + udelay(10); + MACIO_OUT8(KEYLARGO_GPIO_0+0xe, 0x28); + (void)MACIO_IN8(KEYLARGO_GPIO_0+0xe); + UNLOCK(flags); + udelay(10); + MACIO_OUT32(0x1c000, 0); + mdelay(1); + MACIO_OUT8(0x1a3e0, 0x41); + (void)MACIO_IN8(0x1a3e0); + udelay(10); + LOCK(flags); + MACIO_BIS(KEYLARGO_FCR2, KL2_CARDSEL_16); + (void)MACIO_IN32(KEYLARGO_FCR2); + UNLOCK(flags); + mdelay(100); + + macio->flags |= MACIO_FLAG_AIRPORT_ON; + } else { + LOCK(flags); + MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16); + (void)MACIO_IN32(KEYLARGO_FCR2); + MACIO_OUT8(KL_GPIO_AIRPORT_0, 0); + MACIO_OUT8(KL_GPIO_AIRPORT_1, 0); + MACIO_OUT8(KL_GPIO_AIRPORT_2, 0); + MACIO_OUT8(KL_GPIO_AIRPORT_3, 0); + MACIO_OUT8(KL_GPIO_AIRPORT_4, 0); + (void)MACIO_IN8(KL_GPIO_AIRPORT_4); + UNLOCK(flags); + + macio->flags &= ~MACIO_FLAG_AIRPORT_ON; + } + return 0; +} + +#ifdef CONFIG_SMP +static long __pmac +core99_reset_cpu(struct device_node* node, long param, long value) +{ + unsigned int reset_io = 0; + unsigned long flags; + struct macio_chip* macio; + struct device_node* np; + const int dflt_reset_lines[] = { KL_GPIO_RESET_CPU0, + KL_GPIO_RESET_CPU1, + KL_GPIO_RESET_CPU2, + KL_GPIO_RESET_CPU3 }; + + macio = &macio_chips[0]; + if (macio->type != macio_keylargo) + return -ENODEV; + + np = find_path_device("/cpus"); + if (np == NULL) + return -ENODEV; + for (np = np->child; np != NULL; np = np->sibling) { + u32* num = (u32 *)get_property(np, "reg", NULL); + u32* rst = (u32 *)get_property(np, "soft-reset", NULL); + if (num == NULL || rst == NULL) + continue; + if (param == *num) { + reset_io = *rst; + break; + } + } + if (np == NULL || reset_io == 0) + reset_io = dflt_reset_lines[param]; + + LOCK(flags); + MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE); + (void)MACIO_IN8(reset_io); + udelay(1); + MACIO_OUT8(reset_io, 0); + (void)MACIO_IN8(reset_io); + UNLOCK(flags); + + return 0; +} +#endif /* CONFIG_SMP */ + +static long __pmac +core99_usb_enable(struct device_node* node, long param, long value) +{ + struct macio_chip* macio; + unsigned long flags; + char* prop; + int number; + u32 reg; + + macio = &macio_chips[0]; + if (macio->type != macio_keylargo && macio->type != macio_pangea && + macio->type != macio_intrepid) + return -ENODEV; + + prop = (char *)get_property(node, "AAPL,clock-id", NULL); + if (!prop) + return -ENODEV; + if (strncmp(prop, "usb0u048", 8) == 0) + number = 0; + else if (strncmp(prop, "usb1u148", 8) == 0) + number = 2; + else if (strncmp(prop, "usb2u248", 8) == 0) + number = 4; + else + return -ENODEV; + + /* Sorry for the brute-force locking, but this is only used during + * sleep and the timing seem to be critical + */ + LOCK(flags); + if (value) { + /* Turn ON */ + if (number == 0) { + MACIO_BIC(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1)); + (void)MACIO_IN32(KEYLARGO_FCR0); + UNLOCK(flags); + mdelay(1); + LOCK(flags); + MACIO_BIS(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE); + } else if (number == 2) { + MACIO_BIC(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1)); + UNLOCK(flags); + (void)MACIO_IN32(KEYLARGO_FCR0); + mdelay(1); + LOCK(flags); + MACIO_BIS(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE); + } else if (number == 4) { + MACIO_BIC(KEYLARGO_FCR1, (KL1_USB2_PAD_SUSPEND0 | KL1_USB2_PAD_SUSPEND1)); + UNLOCK(flags); + (void)MACIO_IN32(KEYLARGO_FCR1); + mdelay(1); + LOCK(flags); + MACIO_BIS(KEYLARGO_FCR1, KL1_USB2_CELL_ENABLE); + } + if (number < 4) { + reg = MACIO_IN32(KEYLARGO_FCR4); + reg &= ~(KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) | + KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number)); + reg &= ~(KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) | + KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1)); + MACIO_OUT32(KEYLARGO_FCR4, reg); + (void)MACIO_IN32(KEYLARGO_FCR4); + udelay(10); + } else { + reg = MACIO_IN32(KEYLARGO_FCR3); + reg &= ~(KL3_IT_PORT_WAKEUP_ENABLE(0) | KL3_IT_PORT_RESUME_WAKE_EN(0) | + KL3_IT_PORT_CONNECT_WAKE_EN(0) | KL3_IT_PORT_DISCONNECT_WAKE_EN(0)); + reg &= ~(KL3_IT_PORT_WAKEUP_ENABLE(1) | KL3_IT_PORT_RESUME_WAKE_EN(1) | + KL3_IT_PORT_CONNECT_WAKE_EN(1) | KL3_IT_PORT_DISCONNECT_WAKE_EN(1)); + MACIO_OUT32(KEYLARGO_FCR3, reg); + (void)MACIO_IN32(KEYLARGO_FCR3); + udelay(10); + } + if (macio->type == macio_intrepid) { + /* wait for clock stopped bits to clear */ + u32 test0 = 0, test1 = 0; + u32 status0, status1; + int timeout = 1000; + + UNLOCK(flags); + switch (number) { + case 0: + test0 = UNI_N_CLOCK_STOPPED_USB0; + test1 = UNI_N_CLOCK_STOPPED_USB0PCI; + break; + case 2: + test0 = UNI_N_CLOCK_STOPPED_USB1; + test1 = UNI_N_CLOCK_STOPPED_USB1PCI; + break; + case 4: + test0 = UNI_N_CLOCK_STOPPED_USB2; + test1 = UNI_N_CLOCK_STOPPED_USB2PCI; + break; + } + do { + if (--timeout <= 0) { + printk(KERN_ERR "core99_usb_enable: " + "Timeout waiting for clocks\n"); + break; + } + mdelay(1); + status0 = UN_IN(UNI_N_CLOCK_STOP_STATUS0); + status1 = UN_IN(UNI_N_CLOCK_STOP_STATUS1); + } while ((status0 & test0) | (status1 & test1)); + LOCK(flags); + } + } else { + /* Turn OFF */ + if (number < 4) { + reg = MACIO_IN32(KEYLARGO_FCR4); + reg |= KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) | + KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number); + reg |= KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) | + KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1); + MACIO_OUT32(KEYLARGO_FCR4, reg); + (void)MACIO_IN32(KEYLARGO_FCR4); + udelay(1); + } else { + reg = MACIO_IN32(KEYLARGO_FCR3); + reg |= KL3_IT_PORT_WAKEUP_ENABLE(0) | KL3_IT_PORT_RESUME_WAKE_EN(0) | + KL3_IT_PORT_CONNECT_WAKE_EN(0) | KL3_IT_PORT_DISCONNECT_WAKE_EN(0); + reg |= KL3_IT_PORT_WAKEUP_ENABLE(1) | KL3_IT_PORT_RESUME_WAKE_EN(1) | + KL3_IT_PORT_CONNECT_WAKE_EN(1) | KL3_IT_PORT_DISCONNECT_WAKE_EN(1); + MACIO_OUT32(KEYLARGO_FCR3, reg); + (void)MACIO_IN32(KEYLARGO_FCR3); + udelay(1); + } + if (number == 0) { + if (macio->type != macio_intrepid) + MACIO_BIC(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE); + (void)MACIO_IN32(KEYLARGO_FCR0); + udelay(1); + MACIO_BIS(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1)); + (void)MACIO_IN32(KEYLARGO_FCR0); + } else if (number == 2) { + if (macio->type != macio_intrepid) + MACIO_BIC(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE); + (void)MACIO_IN32(KEYLARGO_FCR0); + udelay(1); + MACIO_BIS(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1)); + (void)MACIO_IN32(KEYLARGO_FCR0); + } else if (number == 4) { + udelay(1); + MACIO_BIS(KEYLARGO_FCR1, (KL1_USB2_PAD_SUSPEND0 | KL1_USB2_PAD_SUSPEND1)); + (void)MACIO_IN32(KEYLARGO_FCR1); + } + udelay(1); + } + UNLOCK(flags); + + return 0; +} + +static long __pmac +core99_firewire_enable(struct device_node* node, long param, long value) +{ + unsigned long flags; + struct macio_chip* macio; + + macio = &macio_chips[0]; + if (macio->type != macio_keylargo && macio->type != macio_pangea && + macio->type != macio_intrepid) + return -ENODEV; + if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED)) + return -ENODEV; + + LOCK(flags); + if (value) { + UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW); + (void)UN_IN(UNI_N_CLOCK_CNTL); + } else { + UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW); + (void)UN_IN(UNI_N_CLOCK_CNTL); + } + UNLOCK(flags); + mdelay(1); + + return 0; +} + +static long __pmac +core99_firewire_cable_power(struct device_node* node, long param, long value) +{ + unsigned long flags; + struct macio_chip* macio; + + /* Trick: we allow NULL node */ + if ((pmac_mb.board_flags & PMAC_MB_HAS_FW_POWER) == 0) + return -ENODEV; + macio = &macio_chips[0]; + if (macio->type != macio_keylargo && macio->type != macio_pangea && + macio->type != macio_intrepid) + return -ENODEV; + if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED)) + return -ENODEV; + + LOCK(flags); + if (value) { + MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 0); + MACIO_IN8(KL_GPIO_FW_CABLE_POWER); + udelay(10); + } else { + MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 4); + MACIO_IN8(KL_GPIO_FW_CABLE_POWER); udelay(10); + } + UNLOCK(flags); + mdelay(1); + + return 0; +} + +static long __pmac +intrepid_aack_delay_enable(struct device_node* node, long param, long value) +{ + unsigned long flags; + + if (uninorth_rev < 0xd2) + return -ENODEV; + + LOCK(flags); + if (param) + UN_BIS(UNI_N_AACK_DELAY, UNI_N_AACK_DELAY_ENABLE); + else + UN_BIC(UNI_N_AACK_DELAY, UNI_N_AACK_DELAY_ENABLE); + UNLOCK(flags); + + return 0; +} + + +#endif /* CONFIG_POWER4 */ + +static long __pmac +core99_read_gpio(struct device_node* node, long param, long value) +{ + struct macio_chip* macio = &macio_chips[0]; + + return MACIO_IN8(param); +} + + +static long __pmac +core99_write_gpio(struct device_node* node, long param, long value) +{ + struct macio_chip* macio = &macio_chips[0]; + + MACIO_OUT8(param, (u8)(value & 0xff)); + return 0; +} + +#ifdef CONFIG_POWER4 + +static long __pmac +g5_gmac_enable(struct device_node* node, long param, long value) +{ + struct macio_chip* macio = &macio_chips[0]; + unsigned long flags; + u8 pbus, pid; + + LOCK(flags); + if (value) { + MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE); + mb(); + k2_skiplist[0] = NULL; + } else { + k2_skiplist[0] = node; + mb(); + MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE); + } + + UNLOCK(flags); + mdelay(1); + + return 0; +} + +static long __pmac +g5_fw_enable(struct device_node* node, long param, long value) +{ + struct macio_chip* macio = &macio_chips[0]; + unsigned long flags; + + LOCK(flags); + if (value) { + MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE); + mb(); + k2_skiplist[1] = NULL; + } else { + k2_skiplist[1] = node; + mb(); + MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE); + } + + UNLOCK(flags); + mdelay(1); + + return 0; +} + +static long __pmac +g5_mpic_enable(struct device_node* node, long param, long value) +{ + unsigned long flags; + + if (node->parent == NULL || strcmp(node->parent->name, "u3")) + return 0; + + LOCK(flags); + UN_BIS(U3_TOGGLE_REG, U3_MPIC_RESET | U3_MPIC_OUTPUT_ENABLE); + UNLOCK(flags); + + return 0; +} + +#ifdef CONFIG_SMP +static long __pmac +g5_reset_cpu(struct device_node* node, long param, long value) +{ + unsigned int reset_io = 0; + unsigned long flags; + struct macio_chip* macio; + struct device_node* np; + + macio = &macio_chips[0]; + if (macio->type != macio_keylargo2) + return -ENODEV; + + np = find_path_device("/cpus"); + if (np == NULL) + return -ENODEV; + for (np = np->child; np != NULL; np = np->sibling) { + u32* num = (u32 *)get_property(np, "reg", NULL); + u32* rst = (u32 *)get_property(np, "soft-reset", NULL); + if (num == NULL || rst == NULL) + continue; + if (param == *num) { + reset_io = *rst; + break; + } + } + if (np == NULL || reset_io == 0) + return -ENODEV; + + LOCK(flags); + MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE); + (void)MACIO_IN8(reset_io); + udelay(1); + MACIO_OUT8(reset_io, 0); + (void)MACIO_IN8(reset_io); + UNLOCK(flags); + + return 0; +} +#endif /* CONFIG_SMP */ + +/* + * This can be called from pmac_smp so isn't static + * + * This takes the second CPU off the bus on dual CPU machines + * running UP + */ +void __pmac g5_phy_disable_cpu1(void) +{ + UN_OUT(U3_API_PHY_CONFIG_1, 0); +} + +#endif /* CONFIG_POWER4 */ + +#ifndef CONFIG_POWER4 + +static void __pmac +keylargo_shutdown(struct macio_chip* macio, int sleep_mode) +{ + u32 temp; + + if (sleep_mode) { + mdelay(1); + MACIO_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND); + (void)MACIO_IN32(KEYLARGO_FCR0); + mdelay(1); + } + + MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE | + KL0_SCC_CELL_ENABLE | + KL0_IRDA_ENABLE | KL0_IRDA_CLK32_ENABLE | + KL0_IRDA_CLK19_ENABLE); + + MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK); + MACIO_BIS(KEYLARGO_MBCR, KL_MBCR_MB0_IDE_ENABLE); + + MACIO_BIC(KEYLARGO_FCR1, + KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT | + KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE | + KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT | + KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE | + KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE | + KL1_EIDE0_ENABLE | KL1_EIDE0_RESET_N | + KL1_EIDE1_ENABLE | KL1_EIDE1_RESET_N | + KL1_UIDE_ENABLE); + + MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT); + MACIO_BIC(KEYLARGO_FCR2, KL2_IOBUS_ENABLE); + + temp = MACIO_IN32(KEYLARGO_FCR3); + if (macio->rev >= 2) { + temp |= KL3_SHUTDOWN_PLL2X; + if (sleep_mode) + temp |= KL3_SHUTDOWN_PLL_TOTAL; + } + + temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 | + KL3_SHUTDOWN_PLLKW35; + if (sleep_mode) + temp |= KL3_SHUTDOWN_PLLKW12; + temp &= ~(KL3_CLK66_ENABLE | KL3_CLK49_ENABLE | KL3_CLK45_ENABLE + | KL3_CLK31_ENABLE | KL3_I2S1_CLK18_ENABLE | KL3_I2S0_CLK18_ENABLE); + if (sleep_mode) + temp &= ~(KL3_TIMER_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE); + MACIO_OUT32(KEYLARGO_FCR3, temp); + + /* Flush posted writes & wait a bit */ + (void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1); +} + +static void __pmac +pangea_shutdown(struct macio_chip* macio, int sleep_mode) +{ + u32 temp; + + MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE | + KL0_SCC_CELL_ENABLE | + KL0_USB0_CELL_ENABLE | KL0_USB1_CELL_ENABLE); + + MACIO_BIC(KEYLARGO_FCR1, + KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT | + KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE | + KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT | + KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE | + KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE | + KL1_UIDE_ENABLE); + if (pmac_mb.board_flags & PMAC_MB_MOBILE) + MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N); + + MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT); + + temp = MACIO_IN32(KEYLARGO_FCR3); + temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 | + KL3_SHUTDOWN_PLLKW35; + temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE | KL3_CLK31_ENABLE + | KL3_I2S0_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE); + if (sleep_mode) + temp &= ~(KL3_VIA_CLK16_ENABLE | KL3_TIMER_CLK18_ENABLE); + MACIO_OUT32(KEYLARGO_FCR3, temp); + + /* Flush posted writes & wait a bit */ + (void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1); +} + +static void __pmac +intrepid_shutdown(struct macio_chip* macio, int sleep_mode) +{ + u32 temp; + + MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE | + KL0_SCC_CELL_ENABLE); + + MACIO_BIC(KEYLARGO_FCR1, + /*KL1_USB2_CELL_ENABLE |*/ + KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT | + KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE | + KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE); + if (pmac_mb.board_flags & PMAC_MB_MOBILE) + MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N); + + temp = MACIO_IN32(KEYLARGO_FCR3); + temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE | + KL3_I2S1_CLK18_ENABLE | KL3_I2S0_CLK18_ENABLE); + if (sleep_mode) + temp &= ~(KL3_TIMER_CLK18_ENABLE | KL3_IT_VIA_CLK32_ENABLE); + MACIO_OUT32(KEYLARGO_FCR3, temp); + + /* Flush posted writes & wait a bit */ + (void)MACIO_IN32(KEYLARGO_FCR0); + mdelay(10); +} + +static int __pmac +core99_sleep(void) +{ + struct macio_chip* macio; + int i; + + macio = &macio_chips[0]; + if (macio->type != macio_keylargo && macio->type != macio_pangea && + macio->type != macio_intrepid) + return -ENODEV; + + /* The device-tree contains that in the hwclock node */ + if (macio->type == macio_intrepid) { + UN_OUT(UNI_N_CLOCK_SPREADING, 0); + mdelay(40); + } + + /* We power off the wireless slot in case it was not done + * by the driver. We don't power it on automatically however + */ + if (macio->flags & MACIO_FLAG_AIRPORT_ON) + core99_airport_enable(macio->of_node, 0, 0); + + /* We power off the FW cable. Should be done by the driver... */ + if (macio->flags & MACIO_FLAG_FW_SUPPORTED) { + core99_firewire_enable(NULL, 0, 0); + core99_firewire_cable_power(NULL, 0, 0); + } + + /* We make sure int. modem is off (in case driver lost it) */ + if (macio->type == macio_keylargo) + core99_modem_enable(macio->of_node, 0, 0); + else + pangea_modem_enable(macio->of_node, 0, 0); + + /* We make sure the sound is off as well */ + core99_sound_chip_enable(macio->of_node, 0, 0); + + /* + * Save various bits of KeyLargo + */ + + /* Save the state of the various GPIOs */ + save_gpio_levels[0] = MACIO_IN32(KEYLARGO_GPIO_LEVELS0); + save_gpio_levels[1] = MACIO_IN32(KEYLARGO_GPIO_LEVELS1); + for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++) + save_gpio_extint[i] = MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+i); + for (i=0; i<KEYLARGO_GPIO_CNT; i++) + save_gpio_normal[i] = MACIO_IN8(KEYLARGO_GPIO_0+i); + + /* Save the FCRs */ + if (macio->type == macio_keylargo) + save_mbcr = MACIO_IN32(KEYLARGO_MBCR); + save_fcr[0] = MACIO_IN32(KEYLARGO_FCR0); + save_fcr[1] = MACIO_IN32(KEYLARGO_FCR1); + save_fcr[2] = MACIO_IN32(KEYLARGO_FCR2); + save_fcr[3] = MACIO_IN32(KEYLARGO_FCR3); + save_fcr[4] = MACIO_IN32(KEYLARGO_FCR4); + if (macio->type == macio_pangea || macio->type == macio_intrepid) + save_fcr[5] = MACIO_IN32(KEYLARGO_FCR5); + + /* Save state & config of DBDMA channels */ + dbdma_save(macio, save_dbdma); + + /* + * Turn off as much as we can + */ + if (macio->type == macio_pangea) + pangea_shutdown(macio, 1); + else if (macio->type == macio_intrepid) + intrepid_shutdown(macio, 1); + else if (macio->type == macio_keylargo) + keylargo_shutdown(macio, 1); + + /* + * Put the host bridge to sleep + */ + + save_unin_clock_ctl = UN_IN(UNI_N_CLOCK_CNTL); + /* Note: do not switch GMAC off, driver does it when necessary, WOL must keep it + * enabled ! + */ + UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl & + ~(/*UNI_N_CLOCK_CNTL_GMAC|*/UNI_N_CLOCK_CNTL_FW/*|UNI_N_CLOCK_CNTL_PCI*/)); + udelay(100); + UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING); + UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_SLEEP); + mdelay(10); + + /* + * FIXME: A bit of black magic with OpenPIC (don't ask me why) + */ + if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) { + MACIO_BIS(0x506e0, 0x00400000); + MACIO_BIS(0x506e0, 0x80000000); + } + return 0; +} + +static int __pmac +core99_wake_up(void) +{ + struct macio_chip* macio; + int i; + + macio = &macio_chips[0]; + if (macio->type != macio_keylargo && macio->type != macio_pangea && + macio->type != macio_intrepid) + return -ENODEV; + + /* + * Wakeup the host bridge + */ + UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL); + udelay(10); + UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING); + udelay(10); + + /* + * Restore KeyLargo + */ + + if (macio->type == macio_keylargo) { + MACIO_OUT32(KEYLARGO_MBCR, save_mbcr); + (void)MACIO_IN32(KEYLARGO_MBCR); udelay(10); + } + MACIO_OUT32(KEYLARGO_FCR0, save_fcr[0]); + (void)MACIO_IN32(KEYLARGO_FCR0); udelay(10); + MACIO_OUT32(KEYLARGO_FCR1, save_fcr[1]); + (void)MACIO_IN32(KEYLARGO_FCR1); udelay(10); + MACIO_OUT32(KEYLARGO_FCR2, save_fcr[2]); + (void)MACIO_IN32(KEYLARGO_FCR2); udelay(10); + MACIO_OUT32(KEYLARGO_FCR3, save_fcr[3]); + (void)MACIO_IN32(KEYLARGO_FCR3); udelay(10); + MACIO_OUT32(KEYLARGO_FCR4, save_fcr[4]); + (void)MACIO_IN32(KEYLARGO_FCR4); udelay(10); + if (macio->type == macio_pangea || macio->type == macio_intrepid) { + MACIO_OUT32(KEYLARGO_FCR5, save_fcr[5]); + (void)MACIO_IN32(KEYLARGO_FCR5); udelay(10); + } + + dbdma_restore(macio, save_dbdma); + + MACIO_OUT32(KEYLARGO_GPIO_LEVELS0, save_gpio_levels[0]); + MACIO_OUT32(KEYLARGO_GPIO_LEVELS1, save_gpio_levels[1]); + for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++) + MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+i, save_gpio_extint[i]); + for (i=0; i<KEYLARGO_GPIO_CNT; i++) + MACIO_OUT8(KEYLARGO_GPIO_0+i, save_gpio_normal[i]); + + /* FIXME more black magic with OpenPIC ... */ + if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) { + MACIO_BIC(0x506e0, 0x00400000); + MACIO_BIC(0x506e0, 0x80000000); + } + + UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl); + udelay(100); + + /* Restore clock spreading */ + if (macio->type == macio_intrepid) { + UN_OUT(UNI_N_CLOCK_SPREADING, 2); + mdelay(40); + } + + return 0; +} + +static long __pmac +core99_sleep_state(struct device_node* node, long param, long value) +{ + /* Param == 1 means to enter the "fake sleep" mode that is + * used for CPU speed switch + */ + if (param == 1) { + if (value == 1) { + UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING); + UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_IDLE2); + } else { + UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL); + udelay(10); + UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING); + udelay(10); + } + return 0; + } + if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0) + return -EPERM; + +#ifdef CONFIG_CPU_FREQ_PMAC + /* XXX should be elsewhere */ + if (machine_is_compatible("PowerBook6,5") || + machine_is_compatible("PowerBook6,4") || + machine_is_compatible("PowerBook5,5") || + machine_is_compatible("PowerBook5,4")) { + struct device_node *volt_gpio_np; + u32 *reg = NULL; + + volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select"); + if (volt_gpio_np != NULL) + reg = (u32 *)get_property(volt_gpio_np, "reg", NULL); + if (reg != NULL) { + /* Set the CPU voltage high if sleeping */ + if (value == 1) { + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, + *reg, 0x05); + } else if (value == 0 && (mfspr(SPRN_HID1) & HID1_DFS)) { + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, + *reg, 0x04); + } + mdelay(2); + } + } +#endif /* CONFIG_CPU_FREQ_PMAC */ + + if (value == 1) + return core99_sleep(); + else if (value == 0) + return core99_wake_up(); + return 0; +} + +#endif /* CONFIG_POWER4 */ + +static long __pmac +generic_dev_can_wake(struct device_node* node, long param, long value) +{ + /* Todo: eventually check we are really dealing with on-board + * video device ... + */ + + if (pmac_mb.board_flags & PMAC_MB_MAY_SLEEP) + pmac_mb.board_flags |= PMAC_MB_CAN_SLEEP; + return 0; +} + +static long __pmac +generic_get_mb_info(struct device_node* node, long param, long value) +{ + switch(param) { + case PMAC_MB_INFO_MODEL: + return pmac_mb.model_id; + case PMAC_MB_INFO_FLAGS: + return pmac_mb.board_flags; + case PMAC_MB_INFO_NAME: + /* hack hack hack... but should work */ + *((const char **)value) = pmac_mb.model_name; + return 0; + } + return -EINVAL; +} + + +/* + * Table definitions + */ + +/* Used on any machine + */ +static struct feature_table_entry any_features[] __pmacdata = { + { PMAC_FTR_GET_MB_INFO, generic_get_mb_info }, + { PMAC_FTR_DEVICE_CAN_WAKE, generic_dev_can_wake }, + { 0, NULL } +}; + +#ifndef CONFIG_POWER4 + +/* OHare based motherboards. Currently, we only use these on the + * 2400,3400 and 3500 series powerbooks. Some older desktops seem + * to have issues with turning on/off those asic cells + */ +static struct feature_table_entry ohare_features[] __pmacdata = { + { PMAC_FTR_SCC_ENABLE, ohare_htw_scc_enable }, + { PMAC_FTR_SWIM3_ENABLE, ohare_floppy_enable }, + { PMAC_FTR_MESH_ENABLE, ohare_mesh_enable }, + { PMAC_FTR_IDE_ENABLE, ohare_ide_enable}, + { PMAC_FTR_IDE_RESET, ohare_ide_reset}, + { PMAC_FTR_SLEEP_STATE, ohare_sleep_state }, + { 0, NULL } +}; + +/* Heathrow desktop machines (Beige G3). + * Separated as some features couldn't be properly tested + * and the serial port control bits appear to confuse it. + */ +static struct feature_table_entry heathrow_desktop_features[] __pmacdata = { + { PMAC_FTR_SWIM3_ENABLE, heathrow_floppy_enable }, + { PMAC_FTR_MESH_ENABLE, heathrow_mesh_enable }, + { PMAC_FTR_IDE_ENABLE, heathrow_ide_enable }, + { PMAC_FTR_IDE_RESET, heathrow_ide_reset }, + { PMAC_FTR_BMAC_ENABLE, heathrow_bmac_enable }, + { 0, NULL } +}; + +/* Heathrow based laptop, that is the Wallstreet and mainstreet + * powerbooks. + */ +static struct feature_table_entry heathrow_laptop_features[] __pmacdata = { + { PMAC_FTR_SCC_ENABLE, ohare_htw_scc_enable }, + { PMAC_FTR_MODEM_ENABLE, heathrow_modem_enable }, + { PMAC_FTR_SWIM3_ENABLE, heathrow_floppy_enable }, + { PMAC_FTR_MESH_ENABLE, heathrow_mesh_enable }, + { PMAC_FTR_IDE_ENABLE, heathrow_ide_enable }, + { PMAC_FTR_IDE_RESET, heathrow_ide_reset }, + { PMAC_FTR_BMAC_ENABLE, heathrow_bmac_enable }, + { PMAC_FTR_SOUND_CHIP_ENABLE, heathrow_sound_enable }, + { PMAC_FTR_SLEEP_STATE, heathrow_sleep_state }, + { 0, NULL } +}; + +/* Paddington based machines + * The lombard (101) powerbook, first iMac models, B&W G3 and Yikes G4. + */ +static struct feature_table_entry paddington_features[] __pmacdata = { + { PMAC_FTR_SCC_ENABLE, ohare_htw_scc_enable }, + { PMAC_FTR_MODEM_ENABLE, heathrow_modem_enable }, + { PMAC_FTR_SWIM3_ENABLE, heathrow_floppy_enable }, + { PMAC_FTR_MESH_ENABLE, heathrow_mesh_enable }, + { PMAC_FTR_IDE_ENABLE, heathrow_ide_enable }, + { PMAC_FTR_IDE_RESET, heathrow_ide_reset }, + { PMAC_FTR_BMAC_ENABLE, heathrow_bmac_enable }, + { PMAC_FTR_SOUND_CHIP_ENABLE, heathrow_sound_enable }, + { PMAC_FTR_SLEEP_STATE, heathrow_sleep_state }, + { 0, NULL } +}; + +/* Core99 & MacRISC 2 machines (all machines released since the + * iBook (included), that is all AGP machines, except pangea + * chipset. The pangea chipset is the "combo" UniNorth/KeyLargo + * used on iBook2 & iMac "flow power". + */ +static struct feature_table_entry core99_features[] __pmacdata = { + { PMAC_FTR_SCC_ENABLE, core99_scc_enable }, + { PMAC_FTR_MODEM_ENABLE, core99_modem_enable }, + { PMAC_FTR_IDE_ENABLE, core99_ide_enable }, + { PMAC_FTR_IDE_RESET, core99_ide_reset }, + { PMAC_FTR_GMAC_ENABLE, core99_gmac_enable }, + { PMAC_FTR_GMAC_PHY_RESET, core99_gmac_phy_reset }, + { PMAC_FTR_SOUND_CHIP_ENABLE, core99_sound_chip_enable }, + { PMAC_FTR_AIRPORT_ENABLE, core99_airport_enable }, + { PMAC_FTR_USB_ENABLE, core99_usb_enable }, + { PMAC_FTR_1394_ENABLE, core99_firewire_enable }, + { PMAC_FTR_1394_CABLE_POWER, core99_firewire_cable_power }, + { PMAC_FTR_SLEEP_STATE, core99_sleep_state }, +#ifdef CONFIG_SMP + { PMAC_FTR_RESET_CPU, core99_reset_cpu }, +#endif /* CONFIG_SMP */ + { PMAC_FTR_READ_GPIO, core99_read_gpio }, + { PMAC_FTR_WRITE_GPIO, core99_write_gpio }, + { 0, NULL } +}; + +/* RackMac + */ +static struct feature_table_entry rackmac_features[] __pmacdata = { + { PMAC_FTR_SCC_ENABLE, core99_scc_enable }, + { PMAC_FTR_IDE_ENABLE, core99_ide_enable }, + { PMAC_FTR_IDE_RESET, core99_ide_reset }, + { PMAC_FTR_GMAC_ENABLE, core99_gmac_enable }, + { PMAC_FTR_GMAC_PHY_RESET, core99_gmac_phy_reset }, + { PMAC_FTR_USB_ENABLE, core99_usb_enable }, + { PMAC_FTR_1394_ENABLE, core99_firewire_enable }, + { PMAC_FTR_1394_CABLE_POWER, core99_firewire_cable_power }, + { PMAC_FTR_SLEEP_STATE, core99_sleep_state }, +#ifdef CONFIG_SMP + { PMAC_FTR_RESET_CPU, core99_reset_cpu }, +#endif /* CONFIG_SMP */ + { PMAC_FTR_READ_GPIO, core99_read_gpio }, + { PMAC_FTR_WRITE_GPIO, core99_write_gpio }, + { 0, NULL } +}; + +/* Pangea features + */ +static struct feature_table_entry pangea_features[] __pmacdata = { + { PMAC_FTR_SCC_ENABLE, core99_scc_enable }, + { PMAC_FTR_MODEM_ENABLE, pangea_modem_enable }, + { PMAC_FTR_IDE_ENABLE, core99_ide_enable }, + { PMAC_FTR_IDE_RESET, core99_ide_reset }, + { PMAC_FTR_GMAC_ENABLE, core99_gmac_enable }, + { PMAC_FTR_GMAC_PHY_RESET, core99_gmac_phy_reset }, + { PMAC_FTR_SOUND_CHIP_ENABLE, core99_sound_chip_enable }, + { PMAC_FTR_AIRPORT_ENABLE, core99_airport_enable }, + { PMAC_FTR_USB_ENABLE, core99_usb_enable }, + { PMAC_FTR_1394_ENABLE, core99_firewire_enable }, + { PMAC_FTR_1394_CABLE_POWER, core99_firewire_cable_power }, + { PMAC_FTR_SLEEP_STATE, core99_sleep_state }, + { PMAC_FTR_READ_GPIO, core99_read_gpio }, + { PMAC_FTR_WRITE_GPIO, core99_write_gpio }, + { 0, NULL } +}; + +/* Intrepid features + */ +static struct feature_table_entry intrepid_features[] __pmacdata = { + { PMAC_FTR_SCC_ENABLE, core99_scc_enable }, + { PMAC_FTR_MODEM_ENABLE, pangea_modem_enable }, + { PMAC_FTR_IDE_ENABLE, core99_ide_enable }, + { PMAC_FTR_IDE_RESET, core99_ide_reset }, + { PMAC_FTR_GMAC_ENABLE, core99_gmac_enable }, + { PMAC_FTR_GMAC_PHY_RESET, core99_gmac_phy_reset }, + { PMAC_FTR_SOUND_CHIP_ENABLE, core99_sound_chip_enable }, + { PMAC_FTR_AIRPORT_ENABLE, core99_airport_enable }, + { PMAC_FTR_USB_ENABLE, core99_usb_enable }, + { PMAC_FTR_1394_ENABLE, core99_firewire_enable }, + { PMAC_FTR_1394_CABLE_POWER, core99_firewire_cable_power }, + { PMAC_FTR_SLEEP_STATE, core99_sleep_state }, + { PMAC_FTR_READ_GPIO, core99_read_gpio }, + { PMAC_FTR_WRITE_GPIO, core99_write_gpio }, + { PMAC_FTR_AACK_DELAY_ENABLE, intrepid_aack_delay_enable }, + { 0, NULL } +}; + +#else /* CONFIG_POWER4 */ + +/* G5 features + */ +static struct feature_table_entry g5_features[] __pmacdata = { + { PMAC_FTR_GMAC_ENABLE, g5_gmac_enable }, + { PMAC_FTR_1394_ENABLE, g5_fw_enable }, + { PMAC_FTR_ENABLE_MPIC, g5_mpic_enable }, +#ifdef CONFIG_SMP + { PMAC_FTR_RESET_CPU, g5_reset_cpu }, +#endif /* CONFIG_SMP */ + { PMAC_FTR_READ_GPIO, core99_read_gpio }, + { PMAC_FTR_WRITE_GPIO, core99_write_gpio }, + { 0, NULL } +}; + +#endif /* CONFIG_POWER4 */ + +static struct pmac_mb_def pmac_mb_defs[] __pmacdata = { +#ifndef CONFIG_POWER4 + /* + * Desktops + */ + + { "AAPL,8500", "PowerMac 8500/8600", + PMAC_TYPE_PSURGE, NULL, + 0 + }, + { "AAPL,9500", "PowerMac 9500/9600", + PMAC_TYPE_PSURGE, NULL, + 0 + }, + { "AAPL,7200", "PowerMac 7200", + PMAC_TYPE_PSURGE, NULL, + 0 + }, + { "AAPL,7300", "PowerMac 7200/7300", + PMAC_TYPE_PSURGE, NULL, + 0 + }, + { "AAPL,7500", "PowerMac 7500", + PMAC_TYPE_PSURGE, NULL, + 0 + }, + { "AAPL,ShinerESB", "Apple Network Server", + PMAC_TYPE_ANS, NULL, + 0 + }, + { "AAPL,e407", "Alchemy", + PMAC_TYPE_ALCHEMY, NULL, + 0 + }, + { "AAPL,e411", "Gazelle", + PMAC_TYPE_GAZELLE, NULL, + 0 + }, + { "AAPL,Gossamer", "PowerMac G3 (Gossamer)", + PMAC_TYPE_GOSSAMER, heathrow_desktop_features, + 0 + }, + { "AAPL,PowerMac G3", "PowerMac G3 (Silk)", + PMAC_TYPE_SILK, heathrow_desktop_features, + 0 + }, + { "PowerMac1,1", "Blue&White G3", + PMAC_TYPE_YOSEMITE, paddington_features, + 0 + }, + { "PowerMac1,2", "PowerMac G4 PCI Graphics", + PMAC_TYPE_YIKES, paddington_features, + 0 + }, + { "PowerMac2,1", "iMac FireWire", + PMAC_TYPE_FW_IMAC, core99_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99 + }, + { "PowerMac2,2", "iMac FireWire", + PMAC_TYPE_FW_IMAC, core99_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99 + }, + { "PowerMac3,1", "PowerMac G4 AGP Graphics", + PMAC_TYPE_SAWTOOTH, core99_features, + PMAC_MB_OLD_CORE99 + }, + { "PowerMac3,2", "PowerMac G4 AGP Graphics", + PMAC_TYPE_SAWTOOTH, core99_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99 + }, + { "PowerMac3,3", "PowerMac G4 AGP Graphics", + PMAC_TYPE_SAWTOOTH, core99_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99 + }, + { "PowerMac3,4", "PowerMac G4 Silver", + PMAC_TYPE_QUICKSILVER, core99_features, + PMAC_MB_MAY_SLEEP + }, + { "PowerMac3,5", "PowerMac G4 Silver", + PMAC_TYPE_QUICKSILVER, core99_features, + PMAC_MB_MAY_SLEEP + }, + { "PowerMac3,6", "PowerMac G4 Windtunnel", + PMAC_TYPE_WINDTUNNEL, core99_features, + PMAC_MB_MAY_SLEEP, + }, + { "PowerMac4,1", "iMac \"Flower Power\"", + PMAC_TYPE_PANGEA_IMAC, pangea_features, + PMAC_MB_MAY_SLEEP + }, + { "PowerMac4,2", "Flat panel iMac", + PMAC_TYPE_FLAT_PANEL_IMAC, pangea_features, + PMAC_MB_CAN_SLEEP + }, + { "PowerMac4,4", "eMac", + PMAC_TYPE_EMAC, core99_features, + PMAC_MB_MAY_SLEEP + }, + { "PowerMac5,1", "PowerMac G4 Cube", + PMAC_TYPE_CUBE, core99_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99 + }, + { "PowerMac6,1", "Flat panel iMac", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_MAY_SLEEP, + }, + { "PowerMac6,3", "Flat panel iMac", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_MAY_SLEEP, + }, + { "PowerMac6,4", "eMac", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_MAY_SLEEP, + }, + { "PowerMac10,1", "Mac mini", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER, + }, + { "iMac,1", "iMac (first generation)", + PMAC_TYPE_ORIG_IMAC, paddington_features, + 0 + }, + + /* + * Xserve's + */ + + { "RackMac1,1", "XServe", + PMAC_TYPE_RACKMAC, rackmac_features, + 0, + }, + { "RackMac1,2", "XServe rev. 2", + PMAC_TYPE_RACKMAC, rackmac_features, + 0, + }, + + /* + * Laptops + */ + + { "AAPL,3400/2400", "PowerBook 3400", + PMAC_TYPE_HOOPER, ohare_features, + PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE + }, + { "AAPL,3500", "PowerBook 3500", + PMAC_TYPE_KANGA, ohare_features, + PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE + }, + { "AAPL,PowerBook1998", "PowerBook Wallstreet", + PMAC_TYPE_WALLSTREET, heathrow_laptop_features, + PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE + }, + { "PowerBook1,1", "PowerBook 101 (Lombard)", + PMAC_TYPE_101_PBOOK, paddington_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_MOBILE + }, + { "PowerBook2,1", "iBook (first generation)", + PMAC_TYPE_ORIG_IBOOK, core99_features, + PMAC_MB_CAN_SLEEP | PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE + }, + { "PowerBook2,2", "iBook FireWire", + PMAC_TYPE_FW_IBOOK, core99_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | + PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE + }, + { "PowerBook3,1", "PowerBook Pismo", + PMAC_TYPE_PISMO, core99_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | + PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE + }, + { "PowerBook3,2", "PowerBook Titanium", + PMAC_TYPE_TITANIUM, core99_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE + }, + { "PowerBook3,3", "PowerBook Titanium II", + PMAC_TYPE_TITANIUM2, core99_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE + }, + { "PowerBook3,4", "PowerBook Titanium III", + PMAC_TYPE_TITANIUM3, core99_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE + }, + { "PowerBook3,5", "PowerBook Titanium IV", + PMAC_TYPE_TITANIUM4, core99_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE + }, + { "PowerBook4,1", "iBook 2", + PMAC_TYPE_IBOOK2, pangea_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE + }, + { "PowerBook4,2", "iBook 2", + PMAC_TYPE_IBOOK2, pangea_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE + }, + { "PowerBook4,3", "iBook 2 rev. 2", + PMAC_TYPE_IBOOK2, pangea_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE + }, + { "PowerBook5,1", "PowerBook G4 17\"", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, + }, + { "PowerBook5,2", "PowerBook G4 15\"", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, + }, + { "PowerBook5,3", "PowerBook G4 17\"", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, + }, + { "PowerBook5,4", "PowerBook G4 15\"", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, + }, + { "PowerBook5,5", "PowerBook G4 17\"", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, + }, + { "PowerBook5,6", "PowerBook G4 15\"", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, + }, + { "PowerBook5,7", "PowerBook G4 17\"", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, + }, + { "PowerBook6,1", "PowerBook G4 12\"", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, + }, + { "PowerBook6,2", "PowerBook G4", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, + }, + { "PowerBook6,3", "iBook G4", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, + }, + { "PowerBook6,4", "PowerBook G4 12\"", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, + }, + { "PowerBook6,5", "iBook G4", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, + }, + { "PowerBook6,8", "PowerBook G4 12\"", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, + }, +#else /* CONFIG_POWER4 */ + { "PowerMac7,2", "PowerMac G5", + PMAC_TYPE_POWERMAC_G5, g5_features, + 0, + }, +#endif /* CONFIG_POWER4 */ +}; + +/* + * The toplevel feature_call callback + */ +long __pmac +pmac_do_feature_call(unsigned int selector, ...) +{ + struct device_node* node; + long param, value; + int i; + feature_call func = NULL; + va_list args; + + if (pmac_mb.features) + for (i=0; pmac_mb.features[i].function; i++) + if (pmac_mb.features[i].selector == selector) { + func = pmac_mb.features[i].function; + break; + } + if (!func) + for (i=0; any_features[i].function; i++) + if (any_features[i].selector == selector) { + func = any_features[i].function; + break; + } + if (!func) + return -ENODEV; + + va_start(args, selector); + node = (struct device_node*)va_arg(args, void*); + param = va_arg(args, long); + value = va_arg(args, long); + va_end(args); + + return func(node, param, value); +} + +static int __init +probe_motherboard(void) +{ + int i; + struct macio_chip* macio = &macio_chips[0]; + const char* model = NULL; + struct device_node *dt; + + /* Lookup known motherboard type in device-tree. First try an + * exact match on the "model" property, then try a "compatible" + * match is none is found. + */ + dt = find_devices("device-tree"); + if (dt != NULL) + model = (const char *) get_property(dt, "model", NULL); + for(i=0; model && i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) { + if (strcmp(model, pmac_mb_defs[i].model_string) == 0) { + pmac_mb = pmac_mb_defs[i]; + goto found; + } + } + for(i=0; i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) { + if (machine_is_compatible(pmac_mb_defs[i].model_string)) { + pmac_mb = pmac_mb_defs[i]; + goto found; + } + } + + /* Fallback to selection depending on mac-io chip type */ + switch(macio->type) { +#ifndef CONFIG_POWER4 + case macio_grand_central: + pmac_mb.model_id = PMAC_TYPE_PSURGE; + pmac_mb.model_name = "Unknown PowerSurge"; + break; + case macio_ohare: + pmac_mb.model_id = PMAC_TYPE_UNKNOWN_OHARE; + pmac_mb.model_name = "Unknown OHare-based"; + break; + case macio_heathrow: + pmac_mb.model_id = PMAC_TYPE_UNKNOWN_HEATHROW; + pmac_mb.model_name = "Unknown Heathrow-based"; + pmac_mb.features = heathrow_desktop_features; + break; + case macio_paddington: + pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PADDINGTON; + pmac_mb.model_name = "Unknown Paddington-based"; + pmac_mb.features = paddington_features; + break; + case macio_keylargo: + pmac_mb.model_id = PMAC_TYPE_UNKNOWN_CORE99; + pmac_mb.model_name = "Unknown Keylargo-based"; + pmac_mb.features = core99_features; + break; + case macio_pangea: + pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PANGEA; + pmac_mb.model_name = "Unknown Pangea-based"; + pmac_mb.features = pangea_features; + break; + case macio_intrepid: + pmac_mb.model_id = PMAC_TYPE_UNKNOWN_INTREPID; + pmac_mb.model_name = "Unknown Intrepid-based"; + pmac_mb.features = intrepid_features; + break; +#else /* CONFIG_POWER4 */ + case macio_keylargo2: + pmac_mb.model_id = PMAC_TYPE_UNKNOWN_K2; + pmac_mb.model_name = "Unknown G5"; + pmac_mb.features = g5_features; + break; +#endif /* CONFIG_POWER4 */ + default: + return -ENODEV; + } +found: +#ifndef CONFIG_POWER4 + /* Fixup Hooper vs. Comet */ + if (pmac_mb.model_id == PMAC_TYPE_HOOPER) { + u32 __iomem * mach_id_ptr = ioremap(0xf3000034, 4); + if (!mach_id_ptr) + return -ENODEV; + /* Here, I used to disable the media-bay on comet. It + * appears this is wrong, the floppy connector is actually + * a kind of media-bay and works with the current driver. + */ + if (__raw_readl(mach_id_ptr) & 0x20000000UL) + pmac_mb.model_id = PMAC_TYPE_COMET; + iounmap(mach_id_ptr); + } +#endif /* CONFIG_POWER4 */ + +#ifdef CONFIG_6xx + /* Set default value of powersave_nap on machines that support it. + * It appears that uninorth rev 3 has a problem with it, we don't + * enable it on those. In theory, the flush-on-lock property is + * supposed to be set when not supported, but I'm not very confident + * that all Apple OF revs did it properly, I do it the paranoid way. + */ + while (uninorth_base && uninorth_rev > 3) { + struct device_node* np = find_path_device("/cpus"); + if (!np || !np->child) { + printk(KERN_WARNING "Can't find CPU(s) in device tree !\n"); + break; + } + np = np->child; + /* Nap mode not supported on SMP */ + if (np->sibling) + break; + /* Nap mode not supported if flush-on-lock property is present */ + if (get_property(np, "flush-on-lock", NULL)) + break; + powersave_nap = 1; + printk(KERN_INFO "Processor NAP mode on idle enabled.\n"); + break; + } + + /* On CPUs that support it (750FX), lowspeed by default during + * NAP mode + */ + powersave_lowspeed = 1; +#endif /* CONFIG_6xx */ +#ifdef CONFIG_POWER4 + powersave_nap = 1; +#endif + /* Check for "mobile" machine */ + if (model && (strncmp(model, "PowerBook", 9) == 0 + || strncmp(model, "iBook", 5) == 0)) + pmac_mb.board_flags |= PMAC_MB_MOBILE; + + + printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name); + return 0; +} + +/* Initialize the Core99 UniNorth host bridge and memory controller + */ +static void __init +probe_uninorth(void) +{ + unsigned long actrl; + + /* Locate core99 Uni-N */ + uninorth_node = of_find_node_by_name(NULL, "uni-n"); + /* Locate G5 u3 */ + if (uninorth_node == NULL) { + uninorth_node = of_find_node_by_name(NULL, "u3"); + uninorth_u3 = 1; + } + if (uninorth_node && uninorth_node->n_addrs > 0) { + unsigned long address = uninorth_node->addrs[0].address; + uninorth_base = ioremap(address, 0x40000); + uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); + if (uninorth_u3) + u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000); + } else + uninorth_node = NULL; + + if (!uninorth_node) + return; + + printk(KERN_INFO "Found %s memory controller & host bridge, revision: %d\n", + uninorth_u3 ? "U3" : "UniNorth", uninorth_rev); + printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base); + + /* Set the arbitrer QAck delay according to what Apple does + */ + if (uninorth_rev < 0x11) { + actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK; + actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 : + UNI_N_ARB_CTRL_QACK_DELAY) << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT; + UN_OUT(UNI_N_ARB_CTRL, actrl); + } + + /* Some more magic as done by them in recent MacOS X on UniNorth + * revs 1.5 to 2.O and Pangea. Seem to toggle the UniN Maxbus/PCI + * memory timeout + */ + if ((uninorth_rev >= 0x11 && uninorth_rev <= 0x24) || uninorth_rev == 0xc0) + UN_OUT(0x2160, UN_IN(0x2160) & 0x00ffffff); +} + +static void __init +probe_one_macio(const char* name, const char* compat, int type) +{ + struct device_node* node; + int i; + volatile u32 __iomem * base; + u32* revp; + + node = find_devices(name); + if (!node || !node->n_addrs) + return; + if (compat) + do { + if (device_is_compatible(node, compat)) + break; + node = node->next; + } while (node); + if (!node) + return; + for(i=0; i<MAX_MACIO_CHIPS; i++) { + if (!macio_chips[i].of_node) + break; + if (macio_chips[i].of_node == node) + return; + } + if (i >= MAX_MACIO_CHIPS) { + printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n"); + printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name); + return; + } + base = ioremap(node->addrs[0].address, node->addrs[0].size); + if (!base) { + printk(KERN_ERR "pmac_feature: Can't map mac-io chip !\n"); + return; + } + if (type == macio_keylargo) { + u32* did = (u32 *)get_property(node, "device-id", NULL); + if (*did == 0x00000025) + type = macio_pangea; + if (*did == 0x0000003e) + type = macio_intrepid; + } + macio_chips[i].of_node = node; + macio_chips[i].type = type; + macio_chips[i].base = base; + macio_chips[i].flags = MACIO_FLAG_SCCB_ON | MACIO_FLAG_SCCB_ON; + macio_chips[i].name = macio_names[type]; + revp = (u32 *)get_property(node, "revision-id", NULL); + if (revp) + macio_chips[i].rev = *revp; + printk(KERN_INFO "Found a %s mac-io controller, rev: %d, mapped at 0x%p\n", + macio_names[type], macio_chips[i].rev, macio_chips[i].base); +} + +static int __init +probe_macios(void) +{ + /* Warning, ordering is important */ + probe_one_macio("gc", NULL, macio_grand_central); + probe_one_macio("ohare", NULL, macio_ohare); + probe_one_macio("pci106b,7", NULL, macio_ohareII); + probe_one_macio("mac-io", "keylargo", macio_keylargo); + probe_one_macio("mac-io", "paddington", macio_paddington); + probe_one_macio("mac-io", "gatwick", macio_gatwick); + probe_one_macio("mac-io", "heathrow", macio_heathrow); + probe_one_macio("mac-io", "K2-Keylargo", macio_keylargo2); + + /* Make sure the "main" macio chip appear first */ + if (macio_chips[0].type == macio_gatwick + && macio_chips[1].type == macio_heathrow) { + struct macio_chip temp = macio_chips[0]; + macio_chips[0] = macio_chips[1]; + macio_chips[1] = temp; + } + if (macio_chips[0].type == macio_ohareII + && macio_chips[1].type == macio_ohare) { + struct macio_chip temp = macio_chips[0]; + macio_chips[0] = macio_chips[1]; + macio_chips[1] = temp; + } + macio_chips[0].lbus.index = 0; + macio_chips[1].lbus.index = 1; + + return (macio_chips[0].of_node == NULL) ? -ENODEV : 0; +} + +static void __init +initial_serial_shutdown(struct device_node* np) +{ + int len; + struct slot_names_prop { + int count; + char name[1]; + } *slots; + char *conn; + int port_type = PMAC_SCC_ASYNC; + int modem = 0; + + slots = (struct slot_names_prop *)get_property(np, "slot-names", &len); + conn = get_property(np, "AAPL,connector", &len); + if (conn && (strcmp(conn, "infrared") == 0)) + port_type = PMAC_SCC_IRDA; + else if (device_is_compatible(np, "cobalt")) + modem = 1; + else if (slots && slots->count > 0) { + if (strcmp(slots->name, "IrDA") == 0) + port_type = PMAC_SCC_IRDA; + else if (strcmp(slots->name, "Modem") == 0) + modem = 1; + } + if (modem) + pmac_call_feature(PMAC_FTR_MODEM_ENABLE, np, 0, 0); + pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, port_type, 0); +} + +static void __init +set_initial_features(void) +{ + struct device_node* np; + + /* That hack appears to be necessary for some StarMax motherboards + * but I'm not too sure it was audited for side-effects on other + * ohare based machines... + * Since I still have difficulties figuring the right way to + * differenciate them all and since that hack was there for a long + * time, I'll keep it around + */ + if (macio_chips[0].type == macio_ohare && !find_devices("via-pmu")) { + struct macio_chip* macio = &macio_chips[0]; + MACIO_OUT32(OHARE_FCR, STARMAX_FEATURES); + } else if (macio_chips[0].type == macio_ohare) { + struct macio_chip* macio = &macio_chips[0]; + MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE); + } else if (macio_chips[1].type == macio_ohare) { + struct macio_chip* macio = &macio_chips[1]; + MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE); + } + +#ifdef CONFIG_POWER4 + if (macio_chips[0].type == macio_keylargo2) { +#ifndef CONFIG_SMP + /* On SMP machines running UP, we have the second CPU eating + * bus cycles. We need to take it off the bus. This is done + * from pmac_smp for SMP kernels running on one CPU + */ + np = of_find_node_by_type(NULL, "cpu"); + if (np != NULL) + np = of_find_node_by_type(np, "cpu"); + if (np != NULL) { + g5_phy_disable_cpu1(); + of_node_put(np); + } +#endif /* CONFIG_SMP */ + /* Enable GMAC for now for PCI probing. It will be disabled + * later on after PCI probe + */ + np = of_find_node_by_name(NULL, "ethernet"); + while(np) { + if (device_is_compatible(np, "K2-GMAC")) + g5_gmac_enable(np, 0, 1); + np = of_find_node_by_name(np, "ethernet"); + } + + /* Enable FW before PCI probe. Will be disabled later on + * Note: We should have a batter way to check that we are + * dealing with uninorth internal cell and not a PCI cell + * on the external PCI. The code below works though. + */ + np = of_find_node_by_name(NULL, "firewire"); + while(np) { + if (device_is_compatible(np, "pci106b,5811")) { + macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED; + g5_fw_enable(np, 0, 1); + } + np = of_find_node_by_name(np, "firewire"); + } + } +#else /* CONFIG_POWER4 */ + + if (macio_chips[0].type == macio_keylargo || + macio_chips[0].type == macio_pangea || + macio_chips[0].type == macio_intrepid) { + /* Enable GMAC for now for PCI probing. It will be disabled + * later on after PCI probe + */ + np = of_find_node_by_name(NULL, "ethernet"); + while(np) { + if (np->parent + && device_is_compatible(np->parent, "uni-north") + && device_is_compatible(np, "gmac")) + core99_gmac_enable(np, 0, 1); + np = of_find_node_by_name(np, "ethernet"); + } + + /* Enable FW before PCI probe. Will be disabled later on + * Note: We should have a batter way to check that we are + * dealing with uninorth internal cell and not a PCI cell + * on the external PCI. The code below works though. + */ + np = of_find_node_by_name(NULL, "firewire"); + while(np) { + if (np->parent + && device_is_compatible(np->parent, "uni-north") + && (device_is_compatible(np, "pci106b,18") || + device_is_compatible(np, "pci106b,30") || + device_is_compatible(np, "pci11c1,5811"))) { + macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED; + core99_firewire_enable(np, 0, 1); + } + np = of_find_node_by_name(np, "firewire"); + } + + /* Enable ATA-100 before PCI probe. */ + np = of_find_node_by_name(NULL, "ata-6"); + while(np) { + if (np->parent + && device_is_compatible(np->parent, "uni-north") + && device_is_compatible(np, "kauai-ata")) { + core99_ata100_enable(np, 1); + } + np = of_find_node_by_name(np, "ata-6"); + } + + /* Switch airport off */ + np = find_devices("radio"); + while(np) { + if (np && np->parent == macio_chips[0].of_node) { + macio_chips[0].flags |= MACIO_FLAG_AIRPORT_ON; + core99_airport_enable(np, 0, 0); + } + np = np->next; + } + } + + /* On all machines that support sound PM, switch sound off */ + if (macio_chips[0].of_node) + pmac_do_feature_call(PMAC_FTR_SOUND_CHIP_ENABLE, + macio_chips[0].of_node, 0, 0); + + /* While on some desktop G3s, we turn it back on */ + if (macio_chips[0].of_node && macio_chips[0].type == macio_heathrow + && (pmac_mb.model_id == PMAC_TYPE_GOSSAMER || + pmac_mb.model_id == PMAC_TYPE_SILK)) { + struct macio_chip* macio = &macio_chips[0]; + MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE); + MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N); + } + + /* Hack for bumping clock speed on the new PowerBooks and the + * iBook G4. This implements the "platform-do-clockspreading" OF + * property. For safety, we also check the product ID in the + * device-tree to make reasonably sure we won't set wrong values + * in the clock chip. + * + * Of course, ultimately, we have to implement a real parser for + * the platform-do-* stuff... + */ + while (machine_is_compatible("PowerBook5,2") || + machine_is_compatible("PowerBook5,3") || + machine_is_compatible("PowerBook6,2") || + machine_is_compatible("PowerBook6,3")) { + struct device_node *ui2c = of_find_node_by_type(NULL, "i2c"); + struct device_node *dt = of_find_node_by_name(NULL, "device-tree"); + u8 buffer[9]; + u32 *productID; + int i, rc, changed = 0; + + if (dt == NULL) + break; + productID = (u32 *)get_property(dt, "pid#", NULL); + if (productID == NULL) + break; + while(ui2c) { + struct device_node *p = of_get_parent(ui2c); + if (p && !strcmp(p->name, "uni-n")) + break; + ui2c = of_find_node_by_type(ui2c, "i2c"); + } + if (ui2c == NULL) + break; + DBG("Trying to bump clock speed for PID: %08x...\n", *productID); + rc = pmac_low_i2c_open(ui2c, 1); + if (rc != 0) + break; + pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined); + rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9); + DBG("read result: %d,", rc); + if (rc != 0) { + pmac_low_i2c_close(ui2c); + break; + } + for (i=0; i<9; i++) + DBG(" %02x", buffer[i]); + DBG("\n"); + + switch(*productID) { + case 0x1182: /* AlBook 12" rev 2 */ + case 0x1183: /* iBook G4 12" */ + buffer[0] = (buffer[0] & 0x8f) | 0x70; + buffer[2] = (buffer[2] & 0x7f) | 0x00; + buffer[5] = (buffer[5] & 0x80) | 0x31; + buffer[6] = (buffer[6] & 0x40) | 0xb0; + buffer[7] = (buffer[7] & 0x00) | 0xc0; + buffer[8] = (buffer[8] & 0x00) | 0x30; + changed = 1; + break; + case 0x3142: /* AlBook 15" (ATI M10) */ + case 0x3143: /* AlBook 17" (ATI M10) */ + buffer[0] = (buffer[0] & 0xaf) | 0x50; + buffer[2] = (buffer[2] & 0x7f) | 0x00; + buffer[5] = (buffer[5] & 0x80) | 0x31; + buffer[6] = (buffer[6] & 0x40) | 0xb0; + buffer[7] = (buffer[7] & 0x00) | 0xd0; + buffer[8] = (buffer[8] & 0x00) | 0x30; + changed = 1; + break; + default: + DBG("i2c-hwclock: Machine model not handled\n"); + break; + } + if (!changed) { + pmac_low_i2c_close(ui2c); + break; + } + pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_stdsub); + rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_write, 0x80, buffer, 9); + DBG("write result: %d,", rc); + pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined); + rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9); + DBG("read result: %d,", rc); + if (rc != 0) { + pmac_low_i2c_close(ui2c); + break; + } + for (i=0; i<9; i++) + DBG(" %02x", buffer[i]); + pmac_low_i2c_close(ui2c); + break; + } + +#endif /* CONFIG_POWER4 */ + + /* On all machines, switch modem & serial ports off */ + np = find_devices("ch-a"); + while(np) { + initial_serial_shutdown(np); + np = np->next; + } + np = find_devices("ch-b"); + while(np) { + initial_serial_shutdown(np); + np = np->next; + } +} + +void __init +pmac_feature_init(void) +{ + /* Detect the UniNorth memory controller */ + probe_uninorth(); + + /* Probe mac-io controllers */ + if (probe_macios()) { + printk(KERN_WARNING "No mac-io chip found\n"); + return; + } + + /* Setup low-level i2c stuffs */ + pmac_init_low_i2c(); + + /* Probe machine type */ + if (probe_motherboard()) + printk(KERN_WARNING "Unknown PowerMac !\n"); + + /* Set some initial features (turn off some chips that will + * be later turned on) + */ + set_initial_features(); +} + +int __init +pmac_feature_late_init(void) +{ + struct device_node* np; + + /* Request some resources late */ + if (uninorth_node) + request_OF_resource(uninorth_node, 0, NULL); + np = find_devices("hammerhead"); + if (np) + request_OF_resource(np, 0, NULL); + np = find_devices("interrupt-controller"); + if (np) + request_OF_resource(np, 0, NULL); + return 0; +} + +device_initcall(pmac_feature_late_init); + +#ifdef CONFIG_POWER4 + +static void dump_HT_speeds(char *name, u32 cfg, u32 frq) +{ + int freqs[16] = { 200,300,400,500,600,800,1000,0,0,0,0,0,0,0,0,0 }; + int bits[8] = { 8,16,0,32,2,4,0,0 }; + int freq = (frq >> 8) & 0xf; + + if (freqs[freq] == 0) + printk("%s: Unknown HT link frequency %x\n", name, freq); + else + printk("%s: %d MHz on main link, (%d in / %d out) bits width\n", + name, freqs[freq], + bits[(cfg >> 28) & 0x7], bits[(cfg >> 24) & 0x7]); +} + +void __init pmac_check_ht_link(void) +{ + u32 ufreq, freq, ucfg, cfg; + struct device_node *pcix_node; + u8 px_bus, px_devfn; + struct pci_controller *px_hose; + + (void)in_be32(u3_ht + U3_HT_LINK_COMMAND); + ucfg = cfg = in_be32(u3_ht + U3_HT_LINK_CONFIG); + ufreq = freq = in_be32(u3_ht + U3_HT_LINK_FREQ); + dump_HT_speeds("U3 HyperTransport", cfg, freq); + + pcix_node = of_find_compatible_node(NULL, "pci", "pci-x"); + if (pcix_node == NULL) { + printk("No PCI-X bridge found\n"); + return; + } + if (pci_device_from_OF_node(pcix_node, &px_bus, &px_devfn) != 0) { + printk("PCI-X bridge found but not matched to pci\n"); + return; + } + px_hose = pci_find_hose_for_OF_device(pcix_node); + if (px_hose == NULL) { + printk("PCI-X bridge found but not matched to host\n"); + return; + } + early_read_config_dword(px_hose, px_bus, px_devfn, 0xc4, &cfg); + early_read_config_dword(px_hose, px_bus, px_devfn, 0xcc, &freq); + dump_HT_speeds("PCI-X HT Uplink", cfg, freq); + early_read_config_dword(px_hose, px_bus, px_devfn, 0xc8, &cfg); + early_read_config_dword(px_hose, px_bus, px_devfn, 0xd0, &freq); + dump_HT_speeds("PCI-X HT Downlink", cfg, freq); +} + +#endif /* CONFIG_POWER4 */ + +/* + * Early video resume hook + */ + +static void (*pmac_early_vresume_proc)(void *data) __pmacdata; +static void *pmac_early_vresume_data __pmacdata; + +void pmac_set_early_video_resume(void (*proc)(void *data), void *data) +{ + if (_machine != _MACH_Pmac) + return; + preempt_disable(); + pmac_early_vresume_proc = proc; + pmac_early_vresume_data = data; + preempt_enable(); +} +EXPORT_SYMBOL(pmac_set_early_video_resume); + +void __pmac pmac_call_early_video_resume(void) +{ + if (pmac_early_vresume_proc) + pmac_early_vresume_proc(pmac_early_vresume_data); +} diff --git a/arch/ppc/platforms/pmac_low_i2c.c b/arch/ppc/platforms/pmac_low_i2c.c new file mode 100644 index 00000000000..d07579f2b8b --- /dev/null +++ b/arch/ppc/platforms/pmac_low_i2c.c @@ -0,0 +1,513 @@ +/* + * arch/ppc/platforms/pmac_low_i2c.c + * + * Copyright (C) 2003 Ben. Herrenschmidt (benh@kernel.crashing.org) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * This file contains some low-level i2c access routines that + * need to be used by various bits of the PowerMac platform code + * at times where the real asynchronous & interrupt driven driver + * cannot be used. The API borrows some semantics from the darwin + * driver in order to ease the implementation of the platform + * properties parser + */ + +#include <linux/config.h> +#include <linux/types.h> +#include <linux/delay.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/adb.h> +#include <linux/pmu.h> +#include <asm/keylargo.h> +#include <asm/uninorth.h> +#include <asm/io.h> +#include <asm/prom.h> +#include <asm/machdep.h> +#include <asm/pmac_low_i2c.h> + +#define MAX_LOW_I2C_HOST 4 + +#if 1 +#define DBG(x...) do {\ + printk(KERN_DEBUG "KW:" x); \ + } while(0) +#else +#define DBGG(x...) +#endif + +struct low_i2c_host; + +typedef int (*low_i2c_func_t)(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len); + +struct low_i2c_host +{ + struct device_node *np; /* OF device node */ + struct semaphore mutex; /* Access mutex for use by i2c-keywest */ + low_i2c_func_t func; /* Access function */ + int is_open : 1; /* Poor man's access control */ + int mode; /* Current mode */ + int channel; /* Current channel */ + int num_channels; /* Number of channels */ + unsigned long base; /* For keywest-i2c, base address */ + int bsteps; /* And register stepping */ + int speed; /* And speed */ +}; + +static struct low_i2c_host low_i2c_hosts[MAX_LOW_I2C_HOST]; + +/* No locking is necessary on allocation, we are running way before + * anything can race with us + */ +static struct low_i2c_host *find_low_i2c_host(struct device_node *np) +{ + int i; + + for (i = 0; i < MAX_LOW_I2C_HOST; i++) + if (low_i2c_hosts[i].np == np) + return &low_i2c_hosts[i]; + return NULL; +} + +/* + * + * i2c-keywest implementation (UniNorth, U2, U3, Keylargo's) + * + */ + +/* + * Keywest i2c definitions borrowed from drivers/i2c/i2c-keywest.h, + * should be moved somewhere in include/asm-ppc/ + */ +/* Register indices */ +typedef enum { + reg_mode = 0, + reg_control, + reg_status, + reg_isr, + reg_ier, + reg_addr, + reg_subaddr, + reg_data +} reg_t; + + +/* Mode register */ +#define KW_I2C_MODE_100KHZ 0x00 +#define KW_I2C_MODE_50KHZ 0x01 +#define KW_I2C_MODE_25KHZ 0x02 +#define KW_I2C_MODE_DUMB 0x00 +#define KW_I2C_MODE_STANDARD 0x04 +#define KW_I2C_MODE_STANDARDSUB 0x08 +#define KW_I2C_MODE_COMBINED 0x0C +#define KW_I2C_MODE_MODE_MASK 0x0C +#define KW_I2C_MODE_CHAN_MASK 0xF0 + +/* Control register */ +#define KW_I2C_CTL_AAK 0x01 +#define KW_I2C_CTL_XADDR 0x02 +#define KW_I2C_CTL_STOP 0x04 +#define KW_I2C_CTL_START 0x08 + +/* Status register */ +#define KW_I2C_STAT_BUSY 0x01 +#define KW_I2C_STAT_LAST_AAK 0x02 +#define KW_I2C_STAT_LAST_RW 0x04 +#define KW_I2C_STAT_SDA 0x08 +#define KW_I2C_STAT_SCL 0x10 + +/* IER & ISR registers */ +#define KW_I2C_IRQ_DATA 0x01 +#define KW_I2C_IRQ_ADDR 0x02 +#define KW_I2C_IRQ_STOP 0x04 +#define KW_I2C_IRQ_START 0x08 +#define KW_I2C_IRQ_MASK 0x0F + +/* State machine states */ +enum { + state_idle, + state_addr, + state_read, + state_write, + state_stop, + state_dead +}; + +#define WRONG_STATE(name) do {\ + printk(KERN_DEBUG "KW: wrong state. Got %s, state: %s (isr: %02x)\n", \ + name, __kw_state_names[state], isr); \ + } while(0) + +static const char *__kw_state_names[] = { + "state_idle", + "state_addr", + "state_read", + "state_write", + "state_stop", + "state_dead" +}; + +static inline u8 __kw_read_reg(struct low_i2c_host *host, reg_t reg) +{ + return in_8(((volatile u8 *)host->base) + + (((unsigned)reg) << host->bsteps)); +} + +static inline void __kw_write_reg(struct low_i2c_host *host, reg_t reg, u8 val) +{ + out_8(((volatile u8 *)host->base) + + (((unsigned)reg) << host->bsteps), val); + (void)__kw_read_reg(host, reg_subaddr); +} + +#define kw_write_reg(reg, val) __kw_write_reg(host, reg, val) +#define kw_read_reg(reg) __kw_read_reg(host, reg) + + +/* Don't schedule, the g5 fan controller is too + * timing sensitive + */ +static u8 kw_wait_interrupt(struct low_i2c_host* host) +{ + int i; + u8 isr; + + for (i = 0; i < 200000; i++) { + isr = kw_read_reg(reg_isr) & KW_I2C_IRQ_MASK; + if (isr != 0) + return isr; + udelay(1); + } + return isr; +} + +static int kw_handle_interrupt(struct low_i2c_host *host, int state, int rw, int *rc, u8 **data, int *len, u8 isr) +{ + u8 ack; + + if (isr == 0) { + if (state != state_stop) { + DBG("KW: Timeout !\n"); + *rc = -EIO; + goto stop; + } + if (state == state_stop) { + ack = kw_read_reg(reg_status); + if (!(ack & KW_I2C_STAT_BUSY)) { + state = state_idle; + kw_write_reg(reg_ier, 0x00); + } + } + return state; + } + + if (isr & KW_I2C_IRQ_ADDR) { + ack = kw_read_reg(reg_status); + if (state != state_addr) { + kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR); + WRONG_STATE("KW_I2C_IRQ_ADDR"); + *rc = -EIO; + goto stop; + } + if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { + *rc = -ENODEV; + DBG("KW: NAK on address\n"); + return state_stop; + } else { + if (rw) { + state = state_read; + if (*len > 1) + kw_write_reg(reg_control, KW_I2C_CTL_AAK); + } else { + state = state_write; + kw_write_reg(reg_data, **data); + (*data)++; (*len)--; + } + } + kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR); + } + + if (isr & KW_I2C_IRQ_DATA) { + if (state == state_read) { + **data = kw_read_reg(reg_data); + (*data)++; (*len)--; + kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); + if ((*len) == 0) + state = state_stop; + else if ((*len) == 1) + kw_write_reg(reg_control, 0); + } else if (state == state_write) { + ack = kw_read_reg(reg_status); + if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { + DBG("KW: nack on data write\n"); + *rc = -EIO; + goto stop; + } else if (*len) { + kw_write_reg(reg_data, **data); + (*data)++; (*len)--; + } else { + kw_write_reg(reg_control, KW_I2C_CTL_STOP); + state = state_stop; + *rc = 0; + } + kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); + } else { + kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); + WRONG_STATE("KW_I2C_IRQ_DATA"); + if (state != state_stop) { + *rc = -EIO; + goto stop; + } + } + } + + if (isr & KW_I2C_IRQ_STOP) { + kw_write_reg(reg_isr, KW_I2C_IRQ_STOP); + if (state != state_stop) { + WRONG_STATE("KW_I2C_IRQ_STOP"); + *rc = -EIO; + } + return state_idle; + } + + if (isr & KW_I2C_IRQ_START) + kw_write_reg(reg_isr, KW_I2C_IRQ_START); + + return state; + + stop: + kw_write_reg(reg_control, KW_I2C_CTL_STOP); + return state_stop; +} + +static int keywest_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 subaddr, u8 *data, int len) +{ + u8 mode_reg = host->speed; + int state = state_addr; + int rc = 0; + + /* Setup mode & subaddress if any */ + switch(host->mode) { + case pmac_low_i2c_mode_dumb: + printk(KERN_ERR "low_i2c: Dumb mode not supported !\n"); + return -EINVAL; + case pmac_low_i2c_mode_std: + mode_reg |= KW_I2C_MODE_STANDARD; + break; + case pmac_low_i2c_mode_stdsub: + mode_reg |= KW_I2C_MODE_STANDARDSUB; + kw_write_reg(reg_subaddr, subaddr); + break; + case pmac_low_i2c_mode_combined: + mode_reg |= KW_I2C_MODE_COMBINED; + kw_write_reg(reg_subaddr, subaddr); + break; + } + + /* Setup channel & clear pending irqs */ + kw_write_reg(reg_isr, kw_read_reg(reg_isr)); + kw_write_reg(reg_mode, mode_reg | (host->channel << 4)); + kw_write_reg(reg_status, 0); + + /* Set up address and r/w bit */ + kw_write_reg(reg_addr, addr); + + /* Start sending address & disable interrupt*/ + kw_write_reg(reg_ier, 0 /*KW_I2C_IRQ_MASK*/); + kw_write_reg(reg_control, KW_I2C_CTL_XADDR); + + /* State machine, to turn into an interrupt handler */ + while(state != state_idle) { + u8 isr = kw_wait_interrupt(host); + state = kw_handle_interrupt(host, state, addr & 1, &rc, &data, &len, isr); + } + + return rc; +} + +static void keywest_low_i2c_add(struct device_node *np) +{ + struct low_i2c_host *host = find_low_i2c_host(NULL); + unsigned long *psteps, *prate, steps, aoffset = 0; + struct device_node *parent; + + if (host == NULL) { + printk(KERN_ERR "low_i2c: Can't allocate host for %s\n", + np->full_name); + return; + } + memset(host, 0, sizeof(*host)); + + init_MUTEX(&host->mutex); + host->np = of_node_get(np); + psteps = (unsigned long *)get_property(np, "AAPL,address-step", NULL); + steps = psteps ? (*psteps) : 0x10; + for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++) + steps >>= 1; + parent = of_get_parent(np); + host->num_channels = 1; + if (parent && parent->name[0] == 'u') { + host->num_channels = 2; + aoffset = 3; + } + /* Select interface rate */ + host->speed = KW_I2C_MODE_100KHZ; + prate = (unsigned long *)get_property(np, "AAPL,i2c-rate", NULL); + if (prate) switch(*prate) { + case 100: + host->speed = KW_I2C_MODE_100KHZ; + break; + case 50: + host->speed = KW_I2C_MODE_50KHZ; + break; + case 25: + host->speed = KW_I2C_MODE_25KHZ; + break; + } + host->mode = pmac_low_i2c_mode_std; + host->base = (unsigned long)ioremap(np->addrs[0].address + aoffset, + np->addrs[0].size); + host->func = keywest_low_i2c_func; +} + +/* + * + * PMU implementation + * + */ + + +#ifdef CONFIG_ADB_PMU + +static int pmu_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len) +{ + // TODO + return -ENODEV; +} + +static void pmu_low_i2c_add(struct device_node *np) +{ + struct low_i2c_host *host = find_low_i2c_host(NULL); + + if (host == NULL) { + printk(KERN_ERR "low_i2c: Can't allocate host for %s\n", + np->full_name); + return; + } + memset(host, 0, sizeof(*host)); + + init_MUTEX(&host->mutex); + host->np = of_node_get(np); + host->num_channels = 3; + host->mode = pmac_low_i2c_mode_std; + host->func = pmu_low_i2c_func; +} + +#endif /* CONFIG_ADB_PMU */ + +void __init pmac_init_low_i2c(void) +{ + struct device_node *np; + + /* Probe keywest-i2c busses */ + np = of_find_compatible_node(NULL, "i2c", "keywest-i2c"); + while(np) { + keywest_low_i2c_add(np); + np = of_find_compatible_node(np, "i2c", "keywest-i2c"); + } + +#ifdef CONFIG_ADB_PMU + /* Probe PMU busses */ + np = of_find_node_by_name(NULL, "via-pmu"); + if (np) + pmu_low_i2c_add(np); +#endif /* CONFIG_ADB_PMU */ + + /* TODO: Add CUDA support as well */ +} + +int pmac_low_i2c_lock(struct device_node *np) +{ + struct low_i2c_host *host = find_low_i2c_host(np); + + if (!host) + return -ENODEV; + down(&host->mutex); + return 0; +} +EXPORT_SYMBOL(pmac_low_i2c_lock); + +int pmac_low_i2c_unlock(struct device_node *np) +{ + struct low_i2c_host *host = find_low_i2c_host(np); + + if (!host) + return -ENODEV; + up(&host->mutex); + return 0; +} +EXPORT_SYMBOL(pmac_low_i2c_unlock); + + +int pmac_low_i2c_open(struct device_node *np, int channel) +{ + struct low_i2c_host *host = find_low_i2c_host(np); + + if (!host) + return -ENODEV; + + if (channel >= host->num_channels) + return -EINVAL; + + down(&host->mutex); + host->is_open = 1; + host->channel = channel; + + return 0; +} +EXPORT_SYMBOL(pmac_low_i2c_open); + +int pmac_low_i2c_close(struct device_node *np) +{ + struct low_i2c_host *host = find_low_i2c_host(np); + + if (!host) + return -ENODEV; + + host->is_open = 0; + up(&host->mutex); + + return 0; +} +EXPORT_SYMBOL(pmac_low_i2c_close); + +int pmac_low_i2c_setmode(struct device_node *np, int mode) +{ + struct low_i2c_host *host = find_low_i2c_host(np); + + if (!host) + return -ENODEV; + WARN_ON(!host->is_open); + host->mode = mode; + + return 0; +} +EXPORT_SYMBOL(pmac_low_i2c_setmode); + +int pmac_low_i2c_xfer(struct device_node *np, u8 addrdir, u8 subaddr, u8 *data, int len) +{ + struct low_i2c_host *host = find_low_i2c_host(np); + + if (!host) + return -ENODEV; + WARN_ON(!host->is_open); + + return host->func(host, addrdir, subaddr, data, len); +} +EXPORT_SYMBOL(pmac_low_i2c_xfer); + diff --git a/arch/ppc/platforms/pmac_nvram.c b/arch/ppc/platforms/pmac_nvram.c new file mode 100644 index 00000000000..c9de6420599 --- /dev/null +++ b/arch/ppc/platforms/pmac_nvram.c @@ -0,0 +1,584 @@ +/* + * arch/ppc/platforms/pmac_nvram.c + * + * Copyright (C) 2002 Benjamin Herrenschmidt (benh@kernel.crashing.org) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Todo: - add support for the OF persistent properties + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/stddef.h> +#include <linux/string.h> +#include <linux/nvram.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/adb.h> +#include <linux/pmu.h> +#include <linux/bootmem.h> +#include <linux/completion.h> +#include <linux/spinlock.h> +#include <asm/sections.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/prom.h> +#include <asm/machdep.h> +#include <asm/nvram.h> + +#define DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +#define NVRAM_SIZE 0x2000 /* 8kB of non-volatile RAM */ + +#define CORE99_SIGNATURE 0x5a +#define CORE99_ADLER_START 0x14 + +/* On Core99, nvram is either a sharp, a micron or an AMD flash */ +#define SM_FLASH_STATUS_DONE 0x80 +#define SM_FLASH_STATUS_ERR 0x38 +#define SM_FLASH_CMD_ERASE_CONFIRM 0xd0 +#define SM_FLASH_CMD_ERASE_SETUP 0x20 +#define SM_FLASH_CMD_RESET 0xff +#define SM_FLASH_CMD_WRITE_SETUP 0x40 +#define SM_FLASH_CMD_CLEAR_STATUS 0x50 +#define SM_FLASH_CMD_READ_STATUS 0x70 + +/* CHRP NVRAM header */ +struct chrp_header { + u8 signature; + u8 cksum; + u16 len; + char name[12]; + u8 data[0]; +}; + +struct core99_header { + struct chrp_header hdr; + u32 adler; + u32 generation; + u32 reserved[2]; +}; + +/* + * Read and write the non-volatile RAM on PowerMacs and CHRP machines. + */ +static int nvram_naddrs; +static volatile unsigned char *nvram_addr; +static volatile unsigned char *nvram_data; +static int nvram_mult, is_core_99; +static int core99_bank = 0; +static int nvram_partitions[3]; +static DEFINE_SPINLOCK(nv_lock); + +extern int pmac_newworld; +extern int system_running; + +static int (*core99_write_bank)(int bank, u8* datas); +static int (*core99_erase_bank)(int bank); + +static char *nvram_image __pmacdata; + + +static unsigned char __pmac core99_nvram_read_byte(int addr) +{ + if (nvram_image == NULL) + return 0xff; + return nvram_image[addr]; +} + +static void __pmac core99_nvram_write_byte(int addr, unsigned char val) +{ + if (nvram_image == NULL) + return; + nvram_image[addr] = val; +} + + +static unsigned char __openfirmware direct_nvram_read_byte(int addr) +{ + return in_8(&nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult]); +} + +static void __openfirmware direct_nvram_write_byte(int addr, unsigned char val) +{ + out_8(&nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult], val); +} + + +static unsigned char __pmac indirect_nvram_read_byte(int addr) +{ + unsigned char val; + unsigned long flags; + + spin_lock_irqsave(&nv_lock, flags); + out_8(nvram_addr, addr >> 5); + val = in_8(&nvram_data[(addr & 0x1f) << 4]); + spin_unlock_irqrestore(&nv_lock, flags); + + return val; +} + +static void __pmac indirect_nvram_write_byte(int addr, unsigned char val) +{ + unsigned long flags; + + spin_lock_irqsave(&nv_lock, flags); + out_8(nvram_addr, addr >> 5); + out_8(&nvram_data[(addr & 0x1f) << 4], val); + spin_unlock_irqrestore(&nv_lock, flags); +} + + +#ifdef CONFIG_ADB_PMU + +static void __pmac pmu_nvram_complete(struct adb_request *req) +{ + if (req->arg) + complete((struct completion *)req->arg); +} + +static unsigned char __pmac pmu_nvram_read_byte(int addr) +{ + struct adb_request req; + DECLARE_COMPLETION(req_complete); + + req.arg = system_state == SYSTEM_RUNNING ? &req_complete : NULL; + if (pmu_request(&req, pmu_nvram_complete, 3, PMU_READ_NVRAM, + (addr >> 8) & 0xff, addr & 0xff)) + return 0xff; + if (system_state == SYSTEM_RUNNING) + wait_for_completion(&req_complete); + while (!req.complete) + pmu_poll(); + return req.reply[0]; +} + +static void __pmac pmu_nvram_write_byte(int addr, unsigned char val) +{ + struct adb_request req; + DECLARE_COMPLETION(req_complete); + + req.arg = system_state == SYSTEM_RUNNING ? &req_complete : NULL; + if (pmu_request(&req, pmu_nvram_complete, 4, PMU_WRITE_NVRAM, + (addr >> 8) & 0xff, addr & 0xff, val)) + return; + if (system_state == SYSTEM_RUNNING) + wait_for_completion(&req_complete); + while (!req.complete) + pmu_poll(); +} + +#endif /* CONFIG_ADB_PMU */ + + +static u8 __pmac chrp_checksum(struct chrp_header* hdr) +{ + u8 *ptr; + u16 sum = hdr->signature; + for (ptr = (u8 *)&hdr->len; ptr < hdr->data; ptr++) + sum += *ptr; + while (sum > 0xFF) + sum = (sum & 0xFF) + (sum>>8); + return sum; +} + +static u32 __pmac core99_calc_adler(u8 *buffer) +{ + int cnt; + u32 low, high; + + buffer += CORE99_ADLER_START; + low = 1; + high = 0; + for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) { + if ((cnt % 5000) == 0) { + high %= 65521UL; + high %= 65521UL; + } + low += buffer[cnt]; + high += low; + } + low %= 65521UL; + high %= 65521UL; + + return (high << 16) | low; +} + +static u32 __pmac core99_check(u8* datas) +{ + struct core99_header* hdr99 = (struct core99_header*)datas; + + if (hdr99->hdr.signature != CORE99_SIGNATURE) { + DBG("Invalid signature\n"); + return 0; + } + if (hdr99->hdr.cksum != chrp_checksum(&hdr99->hdr)) { + DBG("Invalid checksum\n"); + return 0; + } + if (hdr99->adler != core99_calc_adler(datas)) { + DBG("Invalid adler\n"); + return 0; + } + return hdr99->generation; +} + +static int __pmac sm_erase_bank(int bank) +{ + int stat, i; + unsigned long timeout; + + u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE; + + DBG("nvram: Sharp/Micron Erasing bank %d...\n", bank); + + out_8(base, SM_FLASH_CMD_ERASE_SETUP); + out_8(base, SM_FLASH_CMD_ERASE_CONFIRM); + timeout = 0; + do { + if (++timeout > 1000000) { + printk(KERN_ERR "nvram: Sharp/Miron flash erase timeout !\n"); + break; + } + out_8(base, SM_FLASH_CMD_READ_STATUS); + stat = in_8(base); + } while (!(stat & SM_FLASH_STATUS_DONE)); + + out_8(base, SM_FLASH_CMD_CLEAR_STATUS); + out_8(base, SM_FLASH_CMD_RESET); + + for (i=0; i<NVRAM_SIZE; i++) + if (base[i] != 0xff) { + printk(KERN_ERR "nvram: Sharp/Micron flash erase failed !\n"); + return -ENXIO; + } + return 0; +} + +static int __pmac sm_write_bank(int bank, u8* datas) +{ + int i, stat = 0; + unsigned long timeout; + + u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE; + + DBG("nvram: Sharp/Micron Writing bank %d...\n", bank); + + for (i=0; i<NVRAM_SIZE; i++) { + out_8(base+i, SM_FLASH_CMD_WRITE_SETUP); + udelay(1); + out_8(base+i, datas[i]); + timeout = 0; + do { + if (++timeout > 1000000) { + printk(KERN_ERR "nvram: Sharp/Micron flash write timeout !\n"); + break; + } + out_8(base, SM_FLASH_CMD_READ_STATUS); + stat = in_8(base); + } while (!(stat & SM_FLASH_STATUS_DONE)); + if (!(stat & SM_FLASH_STATUS_DONE)) + break; + } + out_8(base, SM_FLASH_CMD_CLEAR_STATUS); + out_8(base, SM_FLASH_CMD_RESET); + for (i=0; i<NVRAM_SIZE; i++) + if (base[i] != datas[i]) { + printk(KERN_ERR "nvram: Sharp/Micron flash write failed !\n"); + return -ENXIO; + } + return 0; +} + +static int __pmac amd_erase_bank(int bank) +{ + int i, stat = 0; + unsigned long timeout; + + u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE; + + DBG("nvram: AMD Erasing bank %d...\n", bank); + + /* Unlock 1 */ + out_8(base+0x555, 0xaa); + udelay(1); + /* Unlock 2 */ + out_8(base+0x2aa, 0x55); + udelay(1); + + /* Sector-Erase */ + out_8(base+0x555, 0x80); + udelay(1); + out_8(base+0x555, 0xaa); + udelay(1); + out_8(base+0x2aa, 0x55); + udelay(1); + out_8(base, 0x30); + udelay(1); + + timeout = 0; + do { + if (++timeout > 1000000) { + printk(KERN_ERR "nvram: AMD flash erase timeout !\n"); + break; + } + stat = in_8(base) ^ in_8(base); + } while (stat != 0); + + /* Reset */ + out_8(base, 0xf0); + udelay(1); + + for (i=0; i<NVRAM_SIZE; i++) + if (base[i] != 0xff) { + printk(KERN_ERR "nvram: AMD flash erase failed !\n"); + return -ENXIO; + } + return 0; +} + +static int __pmac amd_write_bank(int bank, u8* datas) +{ + int i, stat = 0; + unsigned long timeout; + + u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE; + + DBG("nvram: AMD Writing bank %d...\n", bank); + + for (i=0; i<NVRAM_SIZE; i++) { + /* Unlock 1 */ + out_8(base+0x555, 0xaa); + udelay(1); + /* Unlock 2 */ + out_8(base+0x2aa, 0x55); + udelay(1); + + /* Write single word */ + out_8(base+0x555, 0xa0); + udelay(1); + out_8(base+i, datas[i]); + + timeout = 0; + do { + if (++timeout > 1000000) { + printk(KERN_ERR "nvram: AMD flash write timeout !\n"); + break; + } + stat = in_8(base) ^ in_8(base); + } while (stat != 0); + if (stat != 0) + break; + } + + /* Reset */ + out_8(base, 0xf0); + udelay(1); + + for (i=0; i<NVRAM_SIZE; i++) + if (base[i] != datas[i]) { + printk(KERN_ERR "nvram: AMD flash write failed !\n"); + return -ENXIO; + } + return 0; +} + +static void __init lookup_partitions(void) +{ + u8 buffer[17]; + int i, offset; + struct chrp_header* hdr; + + if (pmac_newworld) { + nvram_partitions[pmac_nvram_OF] = -1; + nvram_partitions[pmac_nvram_XPRAM] = -1; + nvram_partitions[pmac_nvram_NR] = -1; + hdr = (struct chrp_header *)buffer; + + offset = 0; + buffer[16] = 0; + do { + for (i=0;i<16;i++) + buffer[i] = nvram_read_byte(offset+i); + if (!strcmp(hdr->name, "common")) + nvram_partitions[pmac_nvram_OF] = offset + 0x10; + if (!strcmp(hdr->name, "APL,MacOS75")) { + nvram_partitions[pmac_nvram_XPRAM] = offset + 0x10; + nvram_partitions[pmac_nvram_NR] = offset + 0x110; + } + offset += (hdr->len * 0x10); + } while(offset < NVRAM_SIZE); + } else { + nvram_partitions[pmac_nvram_OF] = 0x1800; + nvram_partitions[pmac_nvram_XPRAM] = 0x1300; + nvram_partitions[pmac_nvram_NR] = 0x1400; + } + DBG("nvram: OF partition at 0x%x\n", nvram_partitions[pmac_nvram_OF]); + DBG("nvram: XP partition at 0x%x\n", nvram_partitions[pmac_nvram_XPRAM]); + DBG("nvram: NR partition at 0x%x\n", nvram_partitions[pmac_nvram_NR]); +} + +static void __pmac core99_nvram_sync(void) +{ + struct core99_header* hdr99; + unsigned long flags; + + if (!is_core_99 || !nvram_data || !nvram_image) + return; + + spin_lock_irqsave(&nv_lock, flags); + if (!memcmp(nvram_image, (u8*)nvram_data + core99_bank*NVRAM_SIZE, + NVRAM_SIZE)) + goto bail; + + DBG("Updating nvram...\n"); + + hdr99 = (struct core99_header*)nvram_image; + hdr99->generation++; + hdr99->hdr.signature = CORE99_SIGNATURE; + hdr99->hdr.cksum = chrp_checksum(&hdr99->hdr); + hdr99->adler = core99_calc_adler(nvram_image); + core99_bank = core99_bank ? 0 : 1; + if (core99_erase_bank) + if (core99_erase_bank(core99_bank)) { + printk("nvram: Error erasing bank %d\n", core99_bank); + goto bail; + } + if (core99_write_bank) + if (core99_write_bank(core99_bank, nvram_image)) + printk("nvram: Error writing bank %d\n", core99_bank); + bail: + spin_unlock_irqrestore(&nv_lock, flags); + +#ifdef DEBUG + mdelay(2000); +#endif +} + +void __init pmac_nvram_init(void) +{ + struct device_node *dp; + + nvram_naddrs = 0; + + dp = find_devices("nvram"); + if (dp == NULL) { + printk(KERN_ERR "Can't find NVRAM device\n"); + return; + } + nvram_naddrs = dp->n_addrs; + is_core_99 = device_is_compatible(dp, "nvram,flash"); + if (is_core_99) { + int i; + u32 gen_bank0, gen_bank1; + + if (nvram_naddrs < 1) { + printk(KERN_ERR "nvram: no address\n"); + return; + } + nvram_image = alloc_bootmem(NVRAM_SIZE); + if (nvram_image == NULL) { + printk(KERN_ERR "nvram: can't allocate ram image\n"); + return; + } + nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2); + nvram_naddrs = 1; /* Make sure we get the correct case */ + + DBG("nvram: Checking bank 0...\n"); + + gen_bank0 = core99_check((u8 *)nvram_data); + gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE); + core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0; + + DBG("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1); + DBG("nvram: Active bank is: %d\n", core99_bank); + + for (i=0; i<NVRAM_SIZE; i++) + nvram_image[i] = nvram_data[i + core99_bank*NVRAM_SIZE]; + + ppc_md.nvram_read_val = core99_nvram_read_byte; + ppc_md.nvram_write_val = core99_nvram_write_byte; + ppc_md.nvram_sync = core99_nvram_sync; + /* + * Maybe we could be smarter here though making an exclusive list + * of known flash chips is a bit nasty as older OF didn't provide us + * with a useful "compatible" entry. A solution would be to really + * identify the chip using flash id commands and base ourselves on + * a list of known chips IDs + */ + if (device_is_compatible(dp, "amd-0137")) { + core99_erase_bank = amd_erase_bank; + core99_write_bank = amd_write_bank; + } else { + core99_erase_bank = sm_erase_bank; + core99_write_bank = sm_write_bank; + } + } else if (_machine == _MACH_chrp && nvram_naddrs == 1) { + nvram_data = ioremap(dp->addrs[0].address + isa_mem_base, + dp->addrs[0].size); + nvram_mult = 1; + ppc_md.nvram_read_val = direct_nvram_read_byte; + ppc_md.nvram_write_val = direct_nvram_write_byte; + } else if (nvram_naddrs == 1) { + nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size); + nvram_mult = (dp->addrs[0].size + NVRAM_SIZE - 1) / NVRAM_SIZE; + ppc_md.nvram_read_val = direct_nvram_read_byte; + ppc_md.nvram_write_val = direct_nvram_write_byte; + } else if (nvram_naddrs == 2) { + nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size); + nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size); + ppc_md.nvram_read_val = indirect_nvram_read_byte; + ppc_md.nvram_write_val = indirect_nvram_write_byte; + } else if (nvram_naddrs == 0 && sys_ctrler == SYS_CTRLER_PMU) { +#ifdef CONFIG_ADB_PMU + nvram_naddrs = -1; + ppc_md.nvram_read_val = pmu_nvram_read_byte; + ppc_md.nvram_write_val = pmu_nvram_write_byte; +#endif /* CONFIG_ADB_PMU */ + } else { + printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n", + nvram_naddrs); + } + lookup_partitions(); +} + +int __pmac pmac_get_partition(int partition) +{ + return nvram_partitions[partition]; +} + +u8 __pmac pmac_xpram_read(int xpaddr) +{ + int offset = nvram_partitions[pmac_nvram_XPRAM]; + + if (offset < 0) + return 0xff; + + return ppc_md.nvram_read_val(xpaddr + offset); +} + +void __pmac pmac_xpram_write(int xpaddr, u8 data) +{ + int offset = nvram_partitions[pmac_nvram_XPRAM]; + + if (offset < 0) + return; + + ppc_md.nvram_write_val(xpaddr + offset, data); +} + +EXPORT_SYMBOL(pmac_get_partition); +EXPORT_SYMBOL(pmac_xpram_read); +EXPORT_SYMBOL(pmac_xpram_write); diff --git a/arch/ppc/platforms/pmac_pci.c b/arch/ppc/platforms/pmac_pci.c new file mode 100644 index 00000000000..f6ff5192406 --- /dev/null +++ b/arch/ppc/platforms/pmac_pci.c @@ -0,0 +1,1125 @@ +/* + * Support for PCI bridges found on Power Macintoshes. + * At present the "bandit" and "chaos" bridges are supported. + * Fortunately you access configuration space in the same + * way with either bridge. + * + * Copyright (C) 1997 Paul Mackerras (paulus@cs.anu.edu.au) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/string.h> +#include <linux/init.h> +#include <linux/bootmem.h> + +#include <asm/sections.h> +#include <asm/io.h> +#include <asm/prom.h> +#include <asm/pci-bridge.h> +#include <asm/machdep.h> +#include <asm/pmac_feature.h> + +#undef DEBUG + +#ifdef DEBUG +#ifdef CONFIG_XMON +extern void xmon_printf(const char *fmt, ...); +#define DBG(x...) xmon_printf(x) +#else +#define DBG(x...) printk(x) +#endif +#else +#define DBG(x...) +#endif + +static int add_bridge(struct device_node *dev); +extern void pmac_check_ht_link(void); + +/* XXX Could be per-controller, but I don't think we risk anything by + * assuming we won't have both UniNorth and Bandit */ +static int has_uninorth; +#ifdef CONFIG_POWER4 +static struct pci_controller *u3_agp; +#endif /* CONFIG_POWER4 */ + +extern u8 pci_cache_line_size; +extern int pcibios_assign_bus_offset; + +struct device_node *k2_skiplist[2]; + +/* + * Magic constants for enabling cache coherency in the bandit/PSX bridge. + */ +#define BANDIT_DEVID_2 8 +#define BANDIT_REVID 3 + +#define BANDIT_DEVNUM 11 +#define BANDIT_MAGIC 0x50 +#define BANDIT_COHERENT 0x40 + +static int __init +fixup_one_level_bus_range(struct device_node *node, int higher) +{ + for (; node != 0;node = node->sibling) { + int * bus_range; + unsigned int *class_code; + int len; + + /* For PCI<->PCI bridges or CardBus bridges, we go down */ + class_code = (unsigned int *) get_property(node, "class-code", NULL); + if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI && + (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) + continue; + bus_range = (int *) get_property(node, "bus-range", &len); + if (bus_range != NULL && len > 2 * sizeof(int)) { + if (bus_range[1] > higher) + higher = bus_range[1]; + } + higher = fixup_one_level_bus_range(node->child, higher); + } + return higher; +} + +/* This routine fixes the "bus-range" property of all bridges in the + * system since they tend to have their "last" member wrong on macs + * + * Note that the bus numbers manipulated here are OF bus numbers, they + * are not Linux bus numbers. + */ +static void __init +fixup_bus_range(struct device_node *bridge) +{ + int * bus_range; + int len; + + /* Lookup the "bus-range" property for the hose */ + bus_range = (int *) get_property(bridge, "bus-range", &len); + if (bus_range == NULL || len < 2 * sizeof(int)) { + printk(KERN_WARNING "Can't get bus-range for %s\n", + bridge->full_name); + return; + } + bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]); +} + +/* + * Apple MacRISC (U3, UniNorth, Bandit, Chaos) PCI controllers. + * + * The "Bandit" version is present in all early PCI PowerMacs, + * and up to the first ones using Grackle. Some machines may + * have 2 bandit controllers (2 PCI busses). + * + * "Chaos" is used in some "Bandit"-type machines as a bridge + * for the separate display bus. It is accessed the same + * way as bandit, but cannot be probed for devices. It therefore + * has its own config access functions. + * + * The "UniNorth" version is present in all Core99 machines + * (iBook, G4, new IMacs, and all the recent Apple machines). + * It contains 3 controllers in one ASIC. + * + * The U3 is the bridge used on G5 machines. It contains an + * AGP bus which is dealt with the old UniNorth access routines + * and a HyperTransport bus which uses its own set of access + * functions. + */ + +#define MACRISC_CFA0(devfn, off) \ + ((1 << (unsigned long)PCI_SLOT(dev_fn)) \ + | (((unsigned long)PCI_FUNC(dev_fn)) << 8) \ + | (((unsigned long)(off)) & 0xFCUL)) + +#define MACRISC_CFA1(bus, devfn, off) \ + ((((unsigned long)(bus)) << 16) \ + |(((unsigned long)(devfn)) << 8) \ + |(((unsigned long)(off)) & 0xFCUL) \ + |1UL) + +static void volatile __iomem * __pmac +macrisc_cfg_access(struct pci_controller* hose, u8 bus, u8 dev_fn, u8 offset) +{ + unsigned int caddr; + + if (bus == hose->first_busno) { + if (dev_fn < (11 << 3)) + return NULL; + caddr = MACRISC_CFA0(dev_fn, offset); + } else + caddr = MACRISC_CFA1(bus, dev_fn, offset); + + /* Uninorth will return garbage if we don't read back the value ! */ + do { + out_le32(hose->cfg_addr, caddr); + } while (in_le32(hose->cfg_addr) != caddr); + + offset &= has_uninorth ? 0x07 : 0x03; + return hose->cfg_data + offset; +} + +static int __pmac +macrisc_read_config(struct pci_bus *bus, unsigned int devfn, int offset, + int len, u32 *val) +{ + struct pci_controller *hose = bus->sysdata; + void volatile __iomem *addr; + + addr = macrisc_cfg_access(hose, bus->number, devfn, offset); + if (!addr) + return PCIBIOS_DEVICE_NOT_FOUND; + /* + * Note: the caller has already checked that offset is + * suitably aligned and that len is 1, 2 or 4. + */ + switch (len) { + case 1: + *val = in_8(addr); + break; + case 2: + *val = in_le16(addr); + break; + default: + *val = in_le32(addr); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static int __pmac +macrisc_write_config(struct pci_bus *bus, unsigned int devfn, int offset, + int len, u32 val) +{ + struct pci_controller *hose = bus->sysdata; + void volatile __iomem *addr; + + addr = macrisc_cfg_access(hose, bus->number, devfn, offset); + if (!addr) + return PCIBIOS_DEVICE_NOT_FOUND; + /* + * Note: the caller has already checked that offset is + * suitably aligned and that len is 1, 2 or 4. + */ + switch (len) { + case 1: + out_8(addr, val); + (void) in_8(addr); + break; + case 2: + out_le16(addr, val); + (void) in_le16(addr); + break; + default: + out_le32(addr, val); + (void) in_le32(addr); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops macrisc_pci_ops = +{ + macrisc_read_config, + macrisc_write_config +}; + +/* + * Verifiy that a specific (bus, dev_fn) exists on chaos + */ +static int __pmac +chaos_validate_dev(struct pci_bus *bus, int devfn, int offset) +{ + struct device_node *np; + u32 *vendor, *device; + + np = pci_busdev_to_OF_node(bus, devfn); + if (np == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + + vendor = (u32 *)get_property(np, "vendor-id", NULL); + device = (u32 *)get_property(np, "device-id", NULL); + if (vendor == NULL || device == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + + if ((*vendor == 0x106b) && (*device == 3) && (offset >= 0x10) + && (offset != 0x14) && (offset != 0x18) && (offset <= 0x24)) + return PCIBIOS_BAD_REGISTER_NUMBER; + + return PCIBIOS_SUCCESSFUL; +} + +static int __pmac +chaos_read_config(struct pci_bus *bus, unsigned int devfn, int offset, + int len, u32 *val) +{ + int result = chaos_validate_dev(bus, devfn, offset); + if (result == PCIBIOS_BAD_REGISTER_NUMBER) + *val = ~0U; + if (result != PCIBIOS_SUCCESSFUL) + return result; + return macrisc_read_config(bus, devfn, offset, len, val); +} + +static int __pmac +chaos_write_config(struct pci_bus *bus, unsigned int devfn, int offset, + int len, u32 val) +{ + int result = chaos_validate_dev(bus, devfn, offset); + if (result != PCIBIOS_SUCCESSFUL) + return result; + return macrisc_write_config(bus, devfn, offset, len, val); +} + +static struct pci_ops chaos_pci_ops = +{ + chaos_read_config, + chaos_write_config +}; + +#ifdef CONFIG_POWER4 + +/* + * These versions of U3 HyperTransport config space access ops do not + * implement self-view of the HT host yet + */ + +#define U3_HT_CFA0(devfn, off) \ + ((((unsigned long)devfn) << 8) | offset) +#define U3_HT_CFA1(bus, devfn, off) \ + (U3_HT_CFA0(devfn, off) \ + + (((unsigned long)bus) << 16) \ + + 0x01000000UL) + +static void volatile __iomem * __pmac +u3_ht_cfg_access(struct pci_controller* hose, u8 bus, u8 devfn, u8 offset) +{ + if (bus == hose->first_busno) { + /* For now, we don't self probe U3 HT bridge */ + if (PCI_FUNC(devfn) != 0 || PCI_SLOT(devfn) > 7 || + PCI_SLOT(devfn) < 1) + return 0; + return hose->cfg_data + U3_HT_CFA0(devfn, offset); + } else + return hose->cfg_data + U3_HT_CFA1(bus, devfn, offset); +} + +static int __pmac +u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, int offset, + int len, u32 *val) +{ + struct pci_controller *hose = bus->sysdata; + void volatile __iomem *addr; + int i; + + struct device_node *np = pci_busdev_to_OF_node(bus, devfn); + if (np == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + + /* + * When a device in K2 is powered down, we die on config + * cycle accesses. Fix that here. + */ + for (i=0; i<2; i++) + if (k2_skiplist[i] == np) { + switch (len) { + case 1: + *val = 0xff; break; + case 2: + *val = 0xffff; break; + default: + *val = 0xfffffffful; break; + } + return PCIBIOS_SUCCESSFUL; + } + + addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); + if (!addr) + return PCIBIOS_DEVICE_NOT_FOUND; + /* + * Note: the caller has already checked that offset is + * suitably aligned and that len is 1, 2 or 4. + */ + switch (len) { + case 1: + *val = in_8(addr); + break; + case 2: + *val = in_le16(addr); + break; + default: + *val = in_le32(addr); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static int __pmac +u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, int offset, + int len, u32 val) +{ + struct pci_controller *hose = bus->sysdata; + void volatile __iomem *addr; + int i; + + struct device_node *np = pci_busdev_to_OF_node(bus, devfn); + if (np == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + /* + * When a device in K2 is powered down, we die on config + * cycle accesses. Fix that here. + */ + for (i=0; i<2; i++) + if (k2_skiplist[i] == np) + return PCIBIOS_SUCCESSFUL; + + addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); + if (!addr) + return PCIBIOS_DEVICE_NOT_FOUND; + /* + * Note: the caller has already checked that offset is + * suitably aligned and that len is 1, 2 or 4. + */ + switch (len) { + case 1: + out_8(addr, val); + (void) in_8(addr); + break; + case 2: + out_le16(addr, val); + (void) in_le16(addr); + break; + default: + out_le32(addr, val); + (void) in_le32(addr); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops u3_ht_pci_ops = +{ + u3_ht_read_config, + u3_ht_write_config +}; + +#endif /* CONFIG_POWER4 */ + +/* + * For a bandit bridge, turn on cache coherency if necessary. + * N.B. we could clean this up using the hose ops directly. + */ +static void __init +init_bandit(struct pci_controller *bp) +{ + unsigned int vendev, magic; + int rev; + + /* read the word at offset 0 in config space for device 11 */ + out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_VENDOR_ID); + udelay(2); + vendev = in_le32(bp->cfg_data); + if (vendev == (PCI_DEVICE_ID_APPLE_BANDIT << 16) + + PCI_VENDOR_ID_APPLE) { + /* read the revision id */ + out_le32(bp->cfg_addr, + (1UL << BANDIT_DEVNUM) + PCI_REVISION_ID); + udelay(2); + rev = in_8(bp->cfg_data); + if (rev != BANDIT_REVID) + printk(KERN_WARNING + "Unknown revision %d for bandit\n", rev); + } else if (vendev != (BANDIT_DEVID_2 << 16) + PCI_VENDOR_ID_APPLE) { + printk(KERN_WARNING "bandit isn't? (%x)\n", vendev); + return; + } + + /* read the word at offset 0x50 */ + out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + BANDIT_MAGIC); + udelay(2); + magic = in_le32(bp->cfg_data); + if ((magic & BANDIT_COHERENT) != 0) + return; + magic |= BANDIT_COHERENT; + udelay(2); + out_le32(bp->cfg_data, magic); + printk(KERN_INFO "Cache coherency enabled for bandit/PSX\n"); +} + + +/* + * Tweak the PCI-PCI bridge chip on the blue & white G3s. + */ +static void __init +init_p2pbridge(void) +{ + struct device_node *p2pbridge; + struct pci_controller* hose; + u8 bus, devfn; + u16 val; + + /* XXX it would be better here to identify the specific + PCI-PCI bridge chip we have. */ + if ((p2pbridge = find_devices("pci-bridge")) == 0 + || p2pbridge->parent == NULL + || strcmp(p2pbridge->parent->name, "pci") != 0) + return; + if (pci_device_from_OF_node(p2pbridge, &bus, &devfn) < 0) { + DBG("Can't find PCI infos for PCI<->PCI bridge\n"); + return; + } + /* Warning: At this point, we have not yet renumbered all busses. + * So we must use OF walking to find out hose + */ + hose = pci_find_hose_for_OF_device(p2pbridge); + if (!hose) { + DBG("Can't find hose for PCI<->PCI bridge\n"); + return; + } + if (early_read_config_word(hose, bus, devfn, + PCI_BRIDGE_CONTROL, &val) < 0) { + printk(KERN_ERR "init_p2pbridge: couldn't read bridge control\n"); + return; + } + val &= ~PCI_BRIDGE_CTL_MASTER_ABORT; + early_write_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, val); +} + +/* + * Some Apple desktop machines have a NEC PD720100A USB2 controller + * on the motherboard. Open Firmware, on these, will disable the + * EHCI part of it so it behaves like a pair of OHCI's. This fixup + * code re-enables it ;) + */ +static void __init +fixup_nec_usb2(void) +{ + struct device_node *nec; + + for (nec = NULL; (nec = of_find_node_by_name(nec, "usb")) != NULL;) { + struct pci_controller *hose; + u32 data, *prop; + u8 bus, devfn; + + prop = (u32 *)get_property(nec, "vendor-id", NULL); + if (prop == NULL) + continue; + if (0x1033 != *prop) + continue; + prop = (u32 *)get_property(nec, "device-id", NULL); + if (prop == NULL) + continue; + if (0x0035 != *prop) + continue; + prop = (u32 *)get_property(nec, "reg", NULL); + if (prop == NULL) + continue; + devfn = (prop[0] >> 8) & 0xff; + bus = (prop[0] >> 16) & 0xff; + if (PCI_FUNC(devfn) != 0) + continue; + hose = pci_find_hose_for_OF_device(nec); + if (!hose) + continue; + early_read_config_dword(hose, bus, devfn, 0xe4, &data); + if (data & 1UL) { + printk("Found NEC PD720100A USB2 chip with disabled EHCI, fixing up...\n"); + data &= ~1UL; + early_write_config_dword(hose, bus, devfn, 0xe4, data); + early_write_config_byte(hose, bus, devfn | 2, PCI_INTERRUPT_LINE, + nec->intrs[0].line); + } + } +} + +void __init +pmac_find_bridges(void) +{ + struct device_node *np, *root; + struct device_node *ht = NULL; + + root = of_find_node_by_path("/"); + if (root == NULL) { + printk(KERN_CRIT "pmac_find_bridges: can't find root of device tree\n"); + return; + } + for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) { + if (np->name == NULL) + continue; + if (strcmp(np->name, "bandit") == 0 + || strcmp(np->name, "chaos") == 0 + || strcmp(np->name, "pci") == 0) { + if (add_bridge(np) == 0) + of_node_get(np); + } + if (strcmp(np->name, "ht") == 0) { + of_node_get(np); + ht = np; + } + } + of_node_put(root); + + /* Probe HT last as it relies on the agp resources to be already + * setup + */ + if (ht && add_bridge(ht) != 0) + of_node_put(ht); + + init_p2pbridge(); + fixup_nec_usb2(); + + /* We are still having some issues with the Xserve G4, enabling + * some offset between bus number and domains for now when we + * assign all busses should help for now + */ + if (pci_assign_all_busses) + pcibios_assign_bus_offset = 0x10; + +#ifdef CONFIG_POWER4 + /* There is something wrong with DMA on U3/HT. I haven't figured out + * the details yet, but if I set the cache line size to 128 bytes like + * it should, I'm getting memory corruption caused by devices like + * sungem (even without the MWI bit set, but maybe sungem doesn't + * care). Right now, it appears that setting up a 64 bytes line size + * works properly, 64 bytes beeing the max transfer size of HT, I + * suppose this is related the way HT/PCI are hooked together. I still + * need to dive into more specs though to be really sure of what's + * going on. --BenH. + * + * Ok, apparently, it's just that HT can't do more than 64 bytes + * transactions. MWI seem to be meaningless there as well, it may + * be worth nop'ing out pci_set_mwi too though I haven't done that + * yet. + * + * Note that it's a bit different for whatever is in the AGP slot. + * For now, I don't care, but this can become a real issue, we + * should probably hook pci_set_mwi anyway to make sure it sets + * the real cache line size in there. + */ + if (machine_is_compatible("MacRISC4")) + pci_cache_line_size = 16; /* 64 bytes */ + + pmac_check_ht_link(); +#endif /* CONFIG_POWER4 */ +} + +#define GRACKLE_CFA(b, d, o) (0x80 | ((b) << 8) | ((d) << 16) \ + | (((o) & ~3) << 24)) + +#define GRACKLE_PICR1_STG 0x00000040 +#define GRACKLE_PICR1_LOOPSNOOP 0x00000010 + +/* N.B. this is called before bridges is initialized, so we can't + use grackle_pcibios_{read,write}_config_dword. */ +static inline void grackle_set_stg(struct pci_controller* bp, int enable) +{ + unsigned int val; + + out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); + val = in_le32(bp->cfg_data); + val = enable? (val | GRACKLE_PICR1_STG) : + (val & ~GRACKLE_PICR1_STG); + out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); + out_le32(bp->cfg_data, val); + (void)in_le32(bp->cfg_data); +} + +static inline void grackle_set_loop_snoop(struct pci_controller *bp, int enable) +{ + unsigned int val; + + out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); + val = in_le32(bp->cfg_data); + val = enable? (val | GRACKLE_PICR1_LOOPSNOOP) : + (val & ~GRACKLE_PICR1_LOOPSNOOP); + out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); + out_le32(bp->cfg_data, val); + (void)in_le32(bp->cfg_data); +} + +static int __init +setup_uninorth(struct pci_controller* hose, struct reg_property* addr) +{ + pci_assign_all_busses = 1; + has_uninorth = 1; + hose->ops = ¯isc_pci_ops; + hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); + hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000); + /* We "know" that the bridge at f2000000 has the PCI slots. */ + return addr->address == 0xf2000000; +} + +static void __init +setup_bandit(struct pci_controller* hose, struct reg_property* addr) +{ + hose->ops = ¯isc_pci_ops; + hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); + hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000); + init_bandit(hose); +} + +static void __init +setup_chaos(struct pci_controller* hose, struct reg_property* addr) +{ + /* assume a `chaos' bridge */ + hose->ops = &chaos_pci_ops; + hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); + hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000); +} + +#ifdef CONFIG_POWER4 + +static void __init +setup_u3_agp(struct pci_controller* hose, struct reg_property* addr) +{ + /* On G5, we move AGP up to high bus number so we don't need + * to reassign bus numbers for HT. If we ever have P2P bridges + * on AGP, we'll have to move pci_assign_all_busses to the + * pci_controller structure so we enable it for AGP and not for + * HT childs. + * We hard code the address because of the different size of + * the reg address cell, we shall fix that by killing struct + * reg_property and using some accessor functions instead + */ + hose->first_busno = 0xf0; + hose->last_busno = 0xff; + has_uninorth = 1; + hose->ops = ¯isc_pci_ops; + hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000); + hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000); + + u3_agp = hose; +} + +static void __init +setup_u3_ht(struct pci_controller* hose, struct reg_property *addr) +{ + struct device_node *np = (struct device_node *)hose->arch_data; + int i, cur; + + hose->ops = &u3_ht_pci_ops; + + /* We hard code the address because of the different size of + * the reg address cell, we shall fix that by killing struct + * reg_property and using some accessor functions instead + */ + hose->cfg_data = ioremap(0xf2000000, 0x02000000); + + /* + * /ht node doesn't expose a "ranges" property, so we "remove" regions that + * have been allocated to AGP. So far, this version of the code doesn't assign + * any of the 0xfxxxxxxx "fine" memory regions to /ht. + * We need to fix that sooner or later by either parsing all child "ranges" + * properties or figuring out the U3 address space decoding logic and + * then read its configuration register (if any). + */ + hose->io_base_phys = 0xf4000000; + hose->io_base_virt = ioremap(hose->io_base_phys, 0x00400000); + isa_io_base = (unsigned long) hose->io_base_virt; + hose->io_resource.name = np->full_name; + hose->io_resource.start = 0; + hose->io_resource.end = 0x003fffff; + hose->io_resource.flags = IORESOURCE_IO; + hose->pci_mem_offset = 0; + hose->first_busno = 0; + hose->last_busno = 0xef; + hose->mem_resources[0].name = np->full_name; + hose->mem_resources[0].start = 0x80000000; + hose->mem_resources[0].end = 0xefffffff; + hose->mem_resources[0].flags = IORESOURCE_MEM; + + if (u3_agp == NULL) { + DBG("U3 has no AGP, using full resource range\n"); + return; + } + + /* We "remove" the AGP resources from the resources allocated to HT, that + * is we create "holes". However, that code does assumptions that so far + * happen to be true (cross fingers...), typically that resources in the + * AGP node are properly ordered + */ + cur = 0; + for (i=0; i<3; i++) { + struct resource *res = &u3_agp->mem_resources[i]; + if (res->flags != IORESOURCE_MEM) + continue; + /* We don't care about "fine" resources */ + if (res->start >= 0xf0000000) + continue; + /* Check if it's just a matter of "shrinking" us in one direction */ + if (hose->mem_resources[cur].start == res->start) { + DBG("U3/HT: shrink start of %d, %08lx -> %08lx\n", + cur, hose->mem_resources[cur].start, res->end + 1); + hose->mem_resources[cur].start = res->end + 1; + continue; + } + if (hose->mem_resources[cur].end == res->end) { + DBG("U3/HT: shrink end of %d, %08lx -> %08lx\n", + cur, hose->mem_resources[cur].end, res->start - 1); + hose->mem_resources[cur].end = res->start - 1; + continue; + } + /* No, it's not the case, we need a hole */ + if (cur == 2) { + /* not enough resources to make a hole, we drop part of the range */ + printk(KERN_WARNING "Running out of resources for /ht host !\n"); + hose->mem_resources[cur].end = res->start - 1; + continue; + } + cur++; + DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n", + cur-1, res->start - 1, cur, res->end + 1); + hose->mem_resources[cur].name = np->full_name; + hose->mem_resources[cur].flags = IORESOURCE_MEM; + hose->mem_resources[cur].start = res->end + 1; + hose->mem_resources[cur].end = hose->mem_resources[cur-1].end; + hose->mem_resources[cur-1].end = res->start - 1; + } +} + +#endif /* CONFIG_POWER4 */ + +void __init +setup_grackle(struct pci_controller *hose) +{ + setup_indirect_pci(hose, 0xfec00000, 0xfee00000); + if (machine_is_compatible("AAPL,PowerBook1998")) + grackle_set_loop_snoop(hose, 1); +#if 0 /* Disabled for now, HW problems ??? */ + grackle_set_stg(hose, 1); +#endif +} + +/* + * We assume that if we have a G3 powermac, we have one bridge called + * "pci" (a MPC106) and no bandit or chaos bridges, and contrariwise, + * if we have one or more bandit or chaos bridges, we don't have a MPC106. + */ +static int __init +add_bridge(struct device_node *dev) +{ + int len; + struct pci_controller *hose; + struct reg_property *addr; + char* disp_name; + int *bus_range; + int primary = 1; + + DBG("Adding PCI host bridge %s\n", dev->full_name); + + addr = (struct reg_property *) get_property(dev, "reg", &len); + if (addr == NULL || len < sizeof(*addr)) { + printk(KERN_WARNING "Can't use %s: no address\n", + dev->full_name); + return -ENODEV; + } + bus_range = (int *) get_property(dev, "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", + dev->full_name); + } + + hose = pcibios_alloc_controller(); + if (!hose) + return -ENOMEM; + hose->arch_data = dev; + hose->first_busno = bus_range ? bus_range[0] : 0; + hose->last_busno = bus_range ? bus_range[1] : 0xff; + + disp_name = NULL; +#ifdef CONFIG_POWER4 + if (device_is_compatible(dev, "u3-agp")) { + setup_u3_agp(hose, addr); + disp_name = "U3-AGP"; + primary = 0; + } else if (device_is_compatible(dev, "u3-ht")) { + setup_u3_ht(hose, addr); + disp_name = "U3-HT"; + primary = 1; + } else +#endif /* CONFIG_POWER4 */ + if (device_is_compatible(dev, "uni-north")) { + primary = setup_uninorth(hose, addr); + disp_name = "UniNorth"; + } else if (strcmp(dev->name, "pci") == 0) { + /* XXX assume this is a mpc106 (grackle) */ + setup_grackle(hose); + disp_name = "Grackle (MPC106)"; + } else if (strcmp(dev->name, "bandit") == 0) { + setup_bandit(hose, addr); + disp_name = "Bandit"; + } else if (strcmp(dev->name, "chaos") == 0) { + setup_chaos(hose, addr); + disp_name = "Chaos"; + primary = 0; + } + printk(KERN_INFO "Found %s PCI host bridge at 0x%08x. Firmware bus number: %d->%d\n", + disp_name, addr->address, hose->first_busno, hose->last_busno); + DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n", + hose, hose->cfg_addr, hose->cfg_data); + + /* Interpret the "ranges" property */ + /* This also maps the I/O region and sets isa_io/mem_base */ + pci_process_bridge_OF_ranges(hose, dev, primary); + + /* Fixup "bus-range" OF property */ + fixup_bus_range(dev); + + return 0; +} + +static void __init +pcibios_fixup_OF_interrupts(void) +{ + struct pci_dev* dev = NULL; + + /* + * Open Firmware often doesn't initialize the + * PCI_INTERRUPT_LINE config register properly, so we + * should find the device node and apply the interrupt + * obtained from the OF device-tree + */ + for_each_pci_dev(dev) { + struct device_node *node; + node = pci_device_to_OF_node(dev); + /* this is the node, see if it has interrupts */ + if (node && node->n_intrs > 0) + dev->irq = node->intrs[0].line; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + } +} + +void __init +pmac_pcibios_fixup(void) +{ + /* Fixup interrupts according to OF tree */ + pcibios_fixup_OF_interrupts(); +} + +int __pmac +pmac_pci_enable_device_hook(struct pci_dev *dev, int initial) +{ + struct device_node* node; + int updatecfg = 0; + int uninorth_child; + + node = pci_device_to_OF_node(dev); + + /* We don't want to enable USB controllers absent from the OF tree + * (iBook second controller) + */ + if (dev->vendor == PCI_VENDOR_ID_APPLE + && (dev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x10)) + && !node) { + printk(KERN_INFO "Apple USB OHCI %s disabled by firmware\n", + pci_name(dev)); + return -EINVAL; + } + + if (!node) + return 0; + + uninorth_child = node->parent && + device_is_compatible(node->parent, "uni-north"); + + /* Firewire & GMAC were disabled after PCI probe, the driver is + * claiming them, we must re-enable them now. + */ + if (uninorth_child && !strcmp(node->name, "firewire") && + (device_is_compatible(node, "pci106b,18") || + device_is_compatible(node, "pci106b,30") || + device_is_compatible(node, "pci11c1,5811"))) { + pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, node, 0, 1); + pmac_call_feature(PMAC_FTR_1394_ENABLE, node, 0, 1); + updatecfg = 1; + } + if (uninorth_child && !strcmp(node->name, "ethernet") && + device_is_compatible(node, "gmac")) { + pmac_call_feature(PMAC_FTR_GMAC_ENABLE, node, 0, 1); + updatecfg = 1; + } + + if (updatecfg) { + u16 cmd; + + /* + * Make sure PCI is correctly configured + * + * We use old pci_bios versions of the function since, by + * default, gmac is not powered up, and so will be absent + * from the kernel initial PCI lookup. + * + * Should be replaced by 2.4 new PCI mechanisms and really + * register the device. + */ + pci_read_config_word(dev, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE; + pci_write_config_word(dev, PCI_COMMAND, cmd); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 16); + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, pci_cache_line_size); + } + + return 0; +} + +/* We power down some devices after they have been probed. They'll + * be powered back on later on + */ +void __init +pmac_pcibios_after_init(void) +{ + struct device_node* nd; + +#ifdef CONFIG_BLK_DEV_IDE + struct pci_dev *dev = NULL; + + /* OF fails to initialize IDE controllers on macs + * (and maybe other machines) + * + * Ideally, this should be moved to the IDE layer, but we need + * to check specifically with Andre Hedrick how to do it cleanly + * since the common IDE code seem to care about the fact that the + * BIOS may have disabled a controller. + * + * -- BenH + */ + for_each_pci_dev(dev) { + if ((dev->class >> 16) == PCI_BASE_CLASS_STORAGE) + pci_enable_device(dev); + } +#endif /* CONFIG_BLK_DEV_IDE */ + + nd = find_devices("firewire"); + while (nd) { + if (nd->parent && (device_is_compatible(nd, "pci106b,18") || + device_is_compatible(nd, "pci106b,30") || + device_is_compatible(nd, "pci11c1,5811")) + && device_is_compatible(nd->parent, "uni-north")) { + pmac_call_feature(PMAC_FTR_1394_ENABLE, nd, 0, 0); + pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, nd, 0, 0); + } + nd = nd->next; + } + nd = find_devices("ethernet"); + while (nd) { + if (nd->parent && device_is_compatible(nd, "gmac") + && device_is_compatible(nd->parent, "uni-north")) + pmac_call_feature(PMAC_FTR_GMAC_ENABLE, nd, 0, 0); + nd = nd->next; + } +} + +void pmac_pci_fixup_cardbus(struct pci_dev* dev) +{ + if (_machine != _MACH_Pmac) + return; + /* + * Fix the interrupt routing on the various cardbus bridges + * used on powerbooks + */ + if (dev->vendor != PCI_VENDOR_ID_TI) + return; + if (dev->device == PCI_DEVICE_ID_TI_1130 || + dev->device == PCI_DEVICE_ID_TI_1131) { + u8 val; + /* Enable PCI interrupt */ + if (pci_read_config_byte(dev, 0x91, &val) == 0) + pci_write_config_byte(dev, 0x91, val | 0x30); + /* Disable ISA interrupt mode */ + if (pci_read_config_byte(dev, 0x92, &val) == 0) + pci_write_config_byte(dev, 0x92, val & ~0x06); + } + if (dev->device == PCI_DEVICE_ID_TI_1210 || + dev->device == PCI_DEVICE_ID_TI_1211 || + dev->device == PCI_DEVICE_ID_TI_1410 || + dev->device == PCI_DEVICE_ID_TI_1510) { + u8 val; + /* 0x8c == TI122X_IRQMUX, 2 says to route the INTA + signal out the MFUNC0 pin */ + if (pci_read_config_byte(dev, 0x8c, &val) == 0) + pci_write_config_byte(dev, 0x8c, (val & ~0x0f) | 2); + /* Disable ISA interrupt mode */ + if (pci_read_config_byte(dev, 0x92, &val) == 0) + pci_write_config_byte(dev, 0x92, val & ~0x06); + } +} + +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_TI, PCI_ANY_ID, pmac_pci_fixup_cardbus); + +void pmac_pci_fixup_pciata(struct pci_dev* dev) +{ + u8 progif = 0; + + /* + * On PowerMacs, we try to switch any PCI ATA controller to + * fully native mode + */ + if (_machine != _MACH_Pmac) + return; + /* Some controllers don't have the class IDE */ + if (dev->vendor == PCI_VENDOR_ID_PROMISE) + switch(dev->device) { + case PCI_DEVICE_ID_PROMISE_20246: + case PCI_DEVICE_ID_PROMISE_20262: + case PCI_DEVICE_ID_PROMISE_20263: + case PCI_DEVICE_ID_PROMISE_20265: + case PCI_DEVICE_ID_PROMISE_20267: + case PCI_DEVICE_ID_PROMISE_20268: + case PCI_DEVICE_ID_PROMISE_20269: + case PCI_DEVICE_ID_PROMISE_20270: + case PCI_DEVICE_ID_PROMISE_20271: + case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20276: + case PCI_DEVICE_ID_PROMISE_20277: + goto good; + } + /* Others, check PCI class */ + if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) + return; + good: + pci_read_config_byte(dev, PCI_CLASS_PROG, &progif); + if ((progif & 5) != 5) { + printk(KERN_INFO "Forcing PCI IDE into native mode: %s\n", pci_name(dev)); + (void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5); + if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) || + (progif & 5) != 5) + printk(KERN_ERR "Rewrite of PROGIF failed !\n"); + } +} +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pmac_pci_fixup_pciata); + + +/* + * Disable second function on K2-SATA, it's broken + * and disable IO BARs on first one + */ +void __pmac pmac_pci_fixup_k2_sata(struct pci_dev* dev) +{ + int i; + u16 cmd; + + if (PCI_FUNC(dev->devfn) > 0) { + pci_read_config_word(dev, PCI_COMMAND, &cmd); + cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + pci_write_config_word(dev, PCI_COMMAND, cmd); + for (i = 0; i < 6; i++) { + dev->resource[i].start = dev->resource[i].end = 0; + dev->resource[i].flags = 0; + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0); + } + } else { + pci_read_config_word(dev, PCI_COMMAND, &cmd); + cmd &= ~PCI_COMMAND_IO; + pci_write_config_word(dev, PCI_COMMAND, cmd); + for (i = 0; i < 5; i++) { + dev->resource[i].start = dev->resource[i].end = 0; + dev->resource[i].flags = 0; + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0); + } + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, 0x0240, pmac_pci_fixup_k2_sata); diff --git a/arch/ppc/platforms/pmac_pic.c b/arch/ppc/platforms/pmac_pic.c new file mode 100644 index 00000000000..9f92e1bb7f3 --- /dev/null +++ b/arch/ppc/platforms/pmac_pic.c @@ -0,0 +1,689 @@ +/* + * Support for the interrupt controllers found on Power Macintosh, + * currently Apple's "Grand Central" interrupt controller in all + * it's incarnations. OpenPIC support used on newer machines is + * in a separate file + * + * Copyright (C) 1997 Paul Mackerras (paulus@cs.anu.edu.au) + * + * Maintained by Benjamin Herrenschmidt (benh@kernel.crashing.org) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/signal.h> +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/sysdev.h> +#include <linux/adb.h> +#include <linux/pmu.h> + +#include <asm/sections.h> +#include <asm/io.h> +#include <asm/smp.h> +#include <asm/prom.h> +#include <asm/pci-bridge.h> +#include <asm/time.h> +#include <asm/open_pic.h> +#include <asm/xmon.h> +#include <asm/pmac_feature.h> + +#include "pmac_pic.h" + +/* + * XXX this should be in xmon.h, but putting it there means xmon.h + * has to include <linux/interrupt.h> (to get irqreturn_t), which + * causes all sorts of problems. -- paulus + */ +extern irqreturn_t xmon_irq(int, void *, struct pt_regs *); + +struct pmac_irq_hw { + unsigned int event; + unsigned int enable; + unsigned int ack; + unsigned int level; +}; + +/* Default addresses */ +static volatile struct pmac_irq_hw *pmac_irq_hw[4] __pmacdata = { + (struct pmac_irq_hw *) 0xf3000020, + (struct pmac_irq_hw *) 0xf3000010, + (struct pmac_irq_hw *) 0xf4000020, + (struct pmac_irq_hw *) 0xf4000010, +}; + +#define GC_LEVEL_MASK 0x3ff00000 +#define OHARE_LEVEL_MASK 0x1ff00000 +#define HEATHROW_LEVEL_MASK 0x1ff00000 + +static int max_irqs __pmacdata; +static int max_real_irqs __pmacdata; +static u32 level_mask[4] __pmacdata; + +static DEFINE_SPINLOCK(pmac_pic_lock __pmacdata); + + +#define GATWICK_IRQ_POOL_SIZE 10 +static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE] __pmacdata; + +/* + * Mark an irq as "lost". This is only used on the pmac + * since it can lose interrupts (see pmac_set_irq_mask). + * -- Cort + */ +void __pmac +__set_lost(unsigned long irq_nr, int nokick) +{ + if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) { + atomic_inc(&ppc_n_lost_interrupts); + if (!nokick) + set_dec(1); + } +} + +static void __pmac +pmac_mask_and_ack_irq(unsigned int irq_nr) +{ + unsigned long bit = 1UL << (irq_nr & 0x1f); + int i = irq_nr >> 5; + unsigned long flags; + + if ((unsigned)irq_nr >= max_irqs) + return; + + clear_bit(irq_nr, ppc_cached_irq_mask); + if (test_and_clear_bit(irq_nr, ppc_lost_interrupts)) + atomic_dec(&ppc_n_lost_interrupts); + spin_lock_irqsave(&pmac_pic_lock, flags); + out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]); + out_le32(&pmac_irq_hw[i]->ack, bit); + do { + /* make sure ack gets to controller before we enable + interrupts */ + mb(); + } while((in_le32(&pmac_irq_hw[i]->enable) & bit) + != (ppc_cached_irq_mask[i] & bit)); + spin_unlock_irqrestore(&pmac_pic_lock, flags); +} + +static void __pmac pmac_set_irq_mask(unsigned int irq_nr, int nokicklost) +{ + unsigned long bit = 1UL << (irq_nr & 0x1f); + int i = irq_nr >> 5; + unsigned long flags; + + if ((unsigned)irq_nr >= max_irqs) + return; + + spin_lock_irqsave(&pmac_pic_lock, flags); + /* enable unmasked interrupts */ + out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]); + + do { + /* make sure mask gets to controller before we + return to user */ + mb(); + } while((in_le32(&pmac_irq_hw[i]->enable) & bit) + != (ppc_cached_irq_mask[i] & bit)); + + /* + * Unfortunately, setting the bit in the enable register + * when the device interrupt is already on *doesn't* set + * the bit in the flag register or request another interrupt. + */ + if (bit & ppc_cached_irq_mask[i] & in_le32(&pmac_irq_hw[i]->level)) + __set_lost((ulong)irq_nr, nokicklost); + spin_unlock_irqrestore(&pmac_pic_lock, flags); +} + +/* When an irq gets requested for the first client, if it's an + * edge interrupt, we clear any previous one on the controller + */ +static unsigned int __pmac pmac_startup_irq(unsigned int irq_nr) +{ + unsigned long bit = 1UL << (irq_nr & 0x1f); + int i = irq_nr >> 5; + + if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0) + out_le32(&pmac_irq_hw[i]->ack, bit); + set_bit(irq_nr, ppc_cached_irq_mask); + pmac_set_irq_mask(irq_nr, 0); + + return 0; +} + +static void __pmac pmac_mask_irq(unsigned int irq_nr) +{ + clear_bit(irq_nr, ppc_cached_irq_mask); + pmac_set_irq_mask(irq_nr, 0); + mb(); +} + +static void __pmac pmac_unmask_irq(unsigned int irq_nr) +{ + set_bit(irq_nr, ppc_cached_irq_mask); + pmac_set_irq_mask(irq_nr, 0); +} + +static void __pmac pmac_end_irq(unsigned int irq_nr) +{ + if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)) + && irq_desc[irq_nr].action) { + set_bit(irq_nr, ppc_cached_irq_mask); + pmac_set_irq_mask(irq_nr, 1); + } +} + + +struct hw_interrupt_type pmac_pic = { + .typename = " PMAC-PIC ", + .startup = pmac_startup_irq, + .enable = pmac_unmask_irq, + .disable = pmac_mask_irq, + .ack = pmac_mask_and_ack_irq, + .end = pmac_end_irq, +}; + +struct hw_interrupt_type gatwick_pic = { + .typename = " GATWICK ", + .startup = pmac_startup_irq, + .enable = pmac_unmask_irq, + .disable = pmac_mask_irq, + .ack = pmac_mask_and_ack_irq, + .end = pmac_end_irq, +}; + +static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs) +{ + int irq, bits; + + for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) { + int i = irq >> 5; + bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i]; + /* We must read level interrupts from the level register */ + bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]); + bits &= ppc_cached_irq_mask[i]; + if (bits == 0) + continue; + irq += __ilog2(bits); + __do_IRQ(irq, regs); + return IRQ_HANDLED; + } + printk("gatwick irq not from gatwick pic\n"); + return IRQ_NONE; +} + +int +pmac_get_irq(struct pt_regs *regs) +{ + int irq; + unsigned long bits = 0; + +#ifdef CONFIG_SMP + void psurge_smp_message_recv(struct pt_regs *); + + /* IPI's are a hack on the powersurge -- Cort */ + if ( smp_processor_id() != 0 ) { + psurge_smp_message_recv(regs); + return -2; /* ignore, already handled */ + } +#endif /* CONFIG_SMP */ + for (irq = max_real_irqs; (irq -= 32) >= 0; ) { + int i = irq >> 5; + bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i]; + /* We must read level interrupts from the level register */ + bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]); + bits &= ppc_cached_irq_mask[i]; + if (bits == 0) + continue; + irq += __ilog2(bits); + break; + } + + return irq; +} + +/* This routine will fix some missing interrupt values in the device tree + * on the gatwick mac-io controller used by some PowerBooks + */ +static void __init +pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base) +{ + struct device_node *node; + int count; + + memset(gatwick_int_pool, 0, sizeof(gatwick_int_pool)); + node = gw->child; + count = 0; + while(node) + { + /* Fix SCC */ + if (strcasecmp(node->name, "escc") == 0) + if (node->child) { + if (node->child->n_intrs < 3) { + node->child->intrs = &gatwick_int_pool[count]; + count += 3; + } + node->child->n_intrs = 3; + node->child->intrs[0].line = 15+irq_base; + node->child->intrs[1].line = 4+irq_base; + node->child->intrs[2].line = 5+irq_base; + printk(KERN_INFO "irq: fixed SCC on second controller (%d,%d,%d)\n", + node->child->intrs[0].line, + node->child->intrs[1].line, + node->child->intrs[2].line); + } + /* Fix media-bay & left SWIM */ + if (strcasecmp(node->name, "media-bay") == 0) { + struct device_node* ya_node; + + if (node->n_intrs == 0) + node->intrs = &gatwick_int_pool[count++]; + node->n_intrs = 1; + node->intrs[0].line = 29+irq_base; + printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n", + node->intrs[0].line); + + ya_node = node->child; + while(ya_node) + { + if (strcasecmp(ya_node->name, "floppy") == 0) { + if (ya_node->n_intrs < 2) { + ya_node->intrs = &gatwick_int_pool[count]; + count += 2; + } + ya_node->n_intrs = 2; + ya_node->intrs[0].line = 19+irq_base; + ya_node->intrs[1].line = 1+irq_base; + printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n", + ya_node->intrs[0].line, ya_node->intrs[1].line); + } + if (strcasecmp(ya_node->name, "ata4") == 0) { + if (ya_node->n_intrs < 2) { + ya_node->intrs = &gatwick_int_pool[count]; + count += 2; + } + ya_node->n_intrs = 2; + ya_node->intrs[0].line = 14+irq_base; + ya_node->intrs[1].line = 3+irq_base; + printk(KERN_INFO "irq: fixed ide on second controller (%d,%d)\n", + ya_node->intrs[0].line, ya_node->intrs[1].line); + } + ya_node = ya_node->sibling; + } + } + node = node->sibling; + } + if (count > 10) { + printk("WARNING !! Gatwick interrupt pool overflow\n"); + printk(" GATWICK_IRQ_POOL_SIZE = %d\n", GATWICK_IRQ_POOL_SIZE); + printk(" requested = %d\n", count); + } +} + +/* + * The PowerBook 3400/2400/3500 can have a combo ethernet/modem + * card which includes an ohare chip that acts as a second interrupt + * controller. If we find this second ohare, set it up and fix the + * interrupt value in the device tree for the ethernet chip. + */ +static int __init enable_second_ohare(void) +{ + unsigned char bus, devfn; + unsigned short cmd; + unsigned long addr; + struct device_node *irqctrler = find_devices("pci106b,7"); + struct device_node *ether; + + if (irqctrler == NULL || irqctrler->n_addrs <= 0) + return -1; + addr = (unsigned long) ioremap(irqctrler->addrs[0].address, 0x40); + pmac_irq_hw[1] = (volatile struct pmac_irq_hw *)(addr + 0x20); + max_irqs = 64; + if (pci_device_from_OF_node(irqctrler, &bus, &devfn) == 0) { + struct pci_controller* hose = pci_find_hose_for_OF_device(irqctrler); + if (!hose) + printk(KERN_ERR "Can't find PCI hose for OHare2 !\n"); + else { + early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; + cmd &= ~PCI_COMMAND_IO; + early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd); + } + } + + /* Fix interrupt for the modem/ethernet combo controller. The number + in the device tree (27) is bogus (correct for the ethernet-only + board but not the combo ethernet/modem board). + The real interrupt is 28 on the second controller -> 28+32 = 60. + */ + ether = find_devices("pci1011,14"); + if (ether && ether->n_intrs > 0) { + ether->intrs[0].line = 60; + printk(KERN_INFO "irq: Fixed ethernet IRQ to %d\n", + ether->intrs[0].line); + } + + /* Return the interrupt number of the cascade */ + return irqctrler->intrs[0].line; +} + +#ifdef CONFIG_POWER4 +static irqreturn_t k2u3_action(int cpl, void *dev_id, struct pt_regs *regs) +{ + int irq; + + irq = openpic2_get_irq(regs); + if (irq != -1) + __do_IRQ(irq, regs); + return IRQ_HANDLED; +} + +static struct irqaction k2u3_cascade_action = { + .handler = k2u3_action, + .flags = 0, + .mask = CPU_MASK_NONE, + .name = "U3->K2 Cascade", +}; +#endif /* CONFIG_POWER4 */ + +#ifdef CONFIG_XMON +static struct irqaction xmon_action = { + .handler = xmon_irq, + .flags = 0, + .mask = CPU_MASK_NONE, + .name = "NMI - XMON" +}; +#endif + +static struct irqaction gatwick_cascade_action = { + .handler = gatwick_action, + .flags = SA_INTERRUPT, + .mask = CPU_MASK_NONE, + .name = "cascade", +}; + +void __init pmac_pic_init(void) +{ + int i; + struct device_node *irqctrler = NULL; + struct device_node *irqctrler2 = NULL; + struct device_node *np; + unsigned long addr; + int irq_cascade = -1; + + /* We first try to detect Apple's new Core99 chipset, since mac-io + * is quite different on those machines and contains an IBM MPIC2. + */ + np = find_type_devices("open-pic"); + while(np) { + if (np->parent && !strcmp(np->parent->name, "u3")) + irqctrler2 = np; + else + irqctrler = np; + np = np->next; + } + if (irqctrler != NULL) + { + if (irqctrler->n_addrs > 0) + { + unsigned char senses[128]; + + printk(KERN_INFO "PowerMac using OpenPIC irq controller at 0x%08x\n", + irqctrler->addrs[0].address); + + prom_get_irq_senses(senses, 0, 128); + OpenPIC_InitSenses = senses; + OpenPIC_NumInitSenses = 128; + ppc_md.get_irq = openpic_get_irq; + pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler, 0, 0); + OpenPIC_Addr = ioremap(irqctrler->addrs[0].address, + irqctrler->addrs[0].size); + openpic_init(0); + +#ifdef CONFIG_POWER4 + if (irqctrler2 != NULL && irqctrler2->n_intrs > 0 && + irqctrler2->n_addrs > 0) { + printk(KERN_INFO "Slave OpenPIC at 0x%08x hooked on IRQ %d\n", + irqctrler2->addrs[0].address, + irqctrler2->intrs[0].line); + pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler2, 0, 0); + OpenPIC2_Addr = ioremap(irqctrler2->addrs[0].address, + irqctrler2->addrs[0].size); + prom_get_irq_senses(senses, PMAC_OPENPIC2_OFFSET, + PMAC_OPENPIC2_OFFSET+128); + OpenPIC_InitSenses = senses; + OpenPIC_NumInitSenses = 128; + openpic2_init(PMAC_OPENPIC2_OFFSET); + + if (setup_irq(irqctrler2->intrs[0].line, + &k2u3_cascade_action)) + printk("Unable to get OpenPIC IRQ for cascade\n"); + } +#endif /* CONFIG_POWER4 */ + +#ifdef CONFIG_XMON + { + struct device_node* pswitch; + int nmi_irq; + + pswitch = find_devices("programmer-switch"); + if (pswitch && pswitch->n_intrs) { + nmi_irq = pswitch->intrs[0].line; + openpic_init_nmi_irq(nmi_irq); + setup_irq(nmi_irq, &xmon_action); + } + } +#endif /* CONFIG_XMON */ + return; + } + irqctrler = NULL; + } + + /* Get the level/edge settings, assume if it's not + * a Grand Central nor an OHare, then it's an Heathrow + * (or Paddington). + */ + if (find_devices("gc")) + level_mask[0] = GC_LEVEL_MASK; + else if (find_devices("ohare")) { + level_mask[0] = OHARE_LEVEL_MASK; + /* We might have a second cascaded ohare */ + level_mask[1] = OHARE_LEVEL_MASK; + } else { + level_mask[0] = HEATHROW_LEVEL_MASK; + level_mask[1] = 0; + /* We might have a second cascaded heathrow */ + level_mask[2] = HEATHROW_LEVEL_MASK; + level_mask[3] = 0; + } + + /* + * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts, + * 1998 G3 Series PowerBooks have 128, + * other powermacs have 32. + * The combo ethernet/modem card for the Powerstar powerbooks + * (2400/3400/3500, ohare based) has a second ohare chip + * effectively making a total of 64. + */ + max_irqs = max_real_irqs = 32; + irqctrler = find_devices("mac-io"); + if (irqctrler) + { + max_real_irqs = 64; + if (irqctrler->next) + max_irqs = 128; + else + max_irqs = 64; + } + for ( i = 0; i < max_real_irqs ; i++ ) + irq_desc[i].handler = &pmac_pic; + + /* get addresses of first controller */ + if (irqctrler) { + if (irqctrler->n_addrs > 0) { + addr = (unsigned long) + ioremap(irqctrler->addrs[0].address, 0x40); + for (i = 0; i < 2; ++i) + pmac_irq_hw[i] = (volatile struct pmac_irq_hw*) + (addr + (2 - i) * 0x10); + } + + /* get addresses of second controller */ + irqctrler = irqctrler->next; + if (irqctrler && irqctrler->n_addrs > 0) { + addr = (unsigned long) + ioremap(irqctrler->addrs[0].address, 0x40); + for (i = 2; i < 4; ++i) + pmac_irq_hw[i] = (volatile struct pmac_irq_hw*) + (addr + (4 - i) * 0x10); + irq_cascade = irqctrler->intrs[0].line; + if (device_is_compatible(irqctrler, "gatwick")) + pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs); + } + } else { + /* older powermacs have a GC (grand central) or ohare at + f3000000, with interrupt control registers at f3000020. */ + addr = (unsigned long) ioremap(0xf3000000, 0x40); + pmac_irq_hw[0] = (volatile struct pmac_irq_hw *) (addr + 0x20); + } + + /* PowerBooks 3400 and 3500 can have a second controller in a second + ohare chip, on the combo ethernet/modem card */ + if (machine_is_compatible("AAPL,3400/2400") + || machine_is_compatible("AAPL,3500")) + irq_cascade = enable_second_ohare(); + + /* disable all interrupts in all controllers */ + for (i = 0; i * 32 < max_irqs; ++i) + out_le32(&pmac_irq_hw[i]->enable, 0); + /* mark level interrupts */ + for (i = 0; i < max_irqs; i++) + if (level_mask[i >> 5] & (1UL << (i & 0x1f))) + irq_desc[i].status = IRQ_LEVEL; + + /* get interrupt line of secondary interrupt controller */ + if (irq_cascade >= 0) { + printk(KERN_INFO "irq: secondary controller on irq %d\n", + (int)irq_cascade); + for ( i = max_real_irqs ; i < max_irqs ; i++ ) + irq_desc[i].handler = &gatwick_pic; + setup_irq(irq_cascade, &gatwick_cascade_action); + } + printk("System has %d possible interrupts\n", max_irqs); + if (max_irqs != max_real_irqs) + printk(KERN_DEBUG "%d interrupts on main controller\n", + max_real_irqs); + +#ifdef CONFIG_XMON + setup_irq(20, &xmon_action); +#endif /* CONFIG_XMON */ +} + +#ifdef CONFIG_PM +/* + * These procedures are used in implementing sleep on the powerbooks. + * sleep_save_intrs() saves the states of all interrupt enables + * and disables all interrupts except for the nominated one. + * sleep_restore_intrs() restores the states of all interrupt enables. + */ +unsigned long sleep_save_mask[2]; + +/* This used to be passed by the PMU driver but that link got + * broken with the new driver model. We use this tweak for now... + */ +static int pmacpic_find_viaint(void) +{ + int viaint = -1; + +#ifdef CONFIG_ADB_PMU + struct device_node *np; + + if (pmu_get_model() != PMU_OHARE_BASED) + goto not_found; + np = of_find_node_by_name(NULL, "via-pmu"); + if (np == NULL) + goto not_found; + viaint = np->intrs[0].line; +#endif /* CONFIG_ADB_PMU */ + +not_found: + return viaint; +} + +static int pmacpic_suspend(struct sys_device *sysdev, u32 state) +{ + int viaint = pmacpic_find_viaint(); + + sleep_save_mask[0] = ppc_cached_irq_mask[0]; + sleep_save_mask[1] = ppc_cached_irq_mask[1]; + ppc_cached_irq_mask[0] = 0; + ppc_cached_irq_mask[1] = 0; + if (viaint > 0) + set_bit(viaint, ppc_cached_irq_mask); + out_le32(&pmac_irq_hw[0]->enable, ppc_cached_irq_mask[0]); + if (max_real_irqs > 32) + out_le32(&pmac_irq_hw[1]->enable, ppc_cached_irq_mask[1]); + (void)in_le32(&pmac_irq_hw[0]->event); + /* make sure mask gets to controller before we return to caller */ + mb(); + (void)in_le32(&pmac_irq_hw[0]->enable); + + return 0; +} + +static int pmacpic_resume(struct sys_device *sysdev) +{ + int i; + + out_le32(&pmac_irq_hw[0]->enable, 0); + if (max_real_irqs > 32) + out_le32(&pmac_irq_hw[1]->enable, 0); + mb(); + for (i = 0; i < max_real_irqs; ++i) + if (test_bit(i, sleep_save_mask)) + pmac_unmask_irq(i); + + return 0; +} + +#endif /* CONFIG_PM */ + +static struct sysdev_class pmacpic_sysclass = { + set_kset_name("pmac_pic"), +}; + +static struct sys_device device_pmacpic = { + .id = 0, + .cls = &pmacpic_sysclass, +}; + +static struct sysdev_driver driver_pmacpic = { +#ifdef CONFIG_PM + .suspend = &pmacpic_suspend, + .resume = &pmacpic_resume, +#endif /* CONFIG_PM */ +}; + +static int __init init_pmacpic_sysfs(void) +{ + if (max_irqs == 0) + return -ENODEV; + + printk(KERN_DEBUG "Registering pmac pic with sysfs...\n"); + sysdev_class_register(&pmacpic_sysclass); + sysdev_register(&device_pmacpic); + sysdev_driver_register(&pmacpic_sysclass, &driver_pmacpic); + return 0; +} + +subsys_initcall(init_pmacpic_sysfs); + diff --git a/arch/ppc/platforms/pmac_pic.h b/arch/ppc/platforms/pmac_pic.h new file mode 100644 index 00000000000..664103dfeef --- /dev/null +++ b/arch/ppc/platforms/pmac_pic.h @@ -0,0 +1,11 @@ +#ifndef __PPC_PLATFORMS_PMAC_PIC_H +#define __PPC_PLATFORMS_PMAC_PIC_H + +#include <linux/irq.h> + +extern struct hw_interrupt_type pmac_pic; + +void pmac_pic_init(void); +int pmac_get_irq(struct pt_regs *regs); + +#endif /* __PPC_PLATFORMS_PMAC_PIC_H */ diff --git a/arch/ppc/platforms/pmac_setup.c b/arch/ppc/platforms/pmac_setup.c new file mode 100644 index 00000000000..4d324b630f4 --- /dev/null +++ b/arch/ppc/platforms/pmac_setup.c @@ -0,0 +1,745 @@ +/* + * arch/ppc/platforms/setup.c + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Adapted for Power Macintosh by Paul Mackerras + * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) + * + * Derived from "arch/alpha/kernel/setup.c" + * Copyright (C) 1995 Linus Torvalds + * + * Maintained by Benjamin Herrenschmidt (benh@kernel.crashing.org) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +/* + * bootup setup stuff.. + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/stddef.h> +#include <linux/unistd.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/user.h> +#include <linux/a.out.h> +#include <linux/tty.h> +#include <linux/string.h> +#include <linux/delay.h> +#include <linux/ioport.h> +#include <linux/major.h> +#include <linux/initrd.h> +#include <linux/vt_kern.h> +#include <linux/console.h> +#include <linux/ide.h> +#include <linux/pci.h> +#include <linux/adb.h> +#include <linux/cuda.h> +#include <linux/pmu.h> +#include <linux/irq.h> +#include <linux/seq_file.h> +#include <linux/root_dev.h> +#include <linux/bitops.h> +#include <linux/suspend.h> + +#include <asm/reg.h> +#include <asm/sections.h> +#include <asm/prom.h> +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/io.h> +#include <asm/pci-bridge.h> +#include <asm/ohare.h> +#include <asm/mediabay.h> +#include <asm/machdep.h> +#include <asm/dma.h> +#include <asm/bootx.h> +#include <asm/cputable.h> +#include <asm/btext.h> +#include <asm/pmac_feature.h> +#include <asm/time.h> +#include <asm/of_device.h> +#include <asm/mmu_context.h> + +#include "pmac_pic.h" +#include "mem_pieces.h" + +#undef SHOW_GATWICK_IRQS + +extern long pmac_time_init(void); +extern unsigned long pmac_get_rtc_time(void); +extern int pmac_set_rtc_time(unsigned long nowtime); +extern void pmac_read_rtc_time(void); +extern void pmac_calibrate_decr(void); +extern void pmac_pcibios_fixup(void); +extern void pmac_find_bridges(void); +extern unsigned long pmac_ide_get_base(int index); +extern void pmac_ide_init_hwif_ports(hw_regs_t *hw, + unsigned long data_port, unsigned long ctrl_port, int *irq); + +extern void pmac_nvram_update(void); +extern unsigned char pmac_nvram_read_byte(int addr); +extern void pmac_nvram_write_byte(int addr, unsigned char val); +extern int pmac_pci_enable_device_hook(struct pci_dev *dev, int initial); +extern void pmac_pcibios_after_init(void); +extern int of_show_percpuinfo(struct seq_file *m, int i); + +struct device_node *memory_node; + +unsigned char drive_info; + +int ppc_override_l2cr = 0; +int ppc_override_l2cr_value; +int has_l2cache = 0; + +static int current_root_goodness = -1; + +extern int pmac_newworld; + +#define DEFAULT_ROOT_DEVICE Root_SDA1 /* sda1 - slightly silly choice */ + +extern void zs_kgdb_hook(int tty_num); +static void ohare_init(void); +#ifdef CONFIG_BOOTX_TEXT +void pmac_progress(char *s, unsigned short hex); +#endif + +sys_ctrler_t sys_ctrler = SYS_CTRLER_UNKNOWN; + +#ifdef CONFIG_SMP +extern struct smp_ops_t psurge_smp_ops; +extern struct smp_ops_t core99_smp_ops; +#endif /* CONFIG_SMP */ + +int __pmac +pmac_show_cpuinfo(struct seq_file *m) +{ + struct device_node *np; + char *pp; + int plen; + int mbmodel = pmac_call_feature(PMAC_FTR_GET_MB_INFO, + NULL, PMAC_MB_INFO_MODEL, 0); + unsigned int mbflags = (unsigned int)pmac_call_feature(PMAC_FTR_GET_MB_INFO, + NULL, PMAC_MB_INFO_FLAGS, 0); + char* mbname; + + if (pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_NAME, (int)&mbname) != 0) + mbname = "Unknown"; + + /* find motherboard type */ + seq_printf(m, "machine\t\t: "); + np = find_devices("device-tree"); + if (np != NULL) { + pp = (char *) get_property(np, "model", NULL); + if (pp != NULL) + seq_printf(m, "%s\n", pp); + else + seq_printf(m, "PowerMac\n"); + pp = (char *) get_property(np, "compatible", &plen); + if (pp != NULL) { + seq_printf(m, "motherboard\t:"); + while (plen > 0) { + int l = strlen(pp) + 1; + seq_printf(m, " %s", pp); + plen -= l; + pp += l; + } + seq_printf(m, "\n"); + } + } else + seq_printf(m, "PowerMac\n"); + + /* print parsed model */ + seq_printf(m, "detected as\t: %d (%s)\n", mbmodel, mbname); + seq_printf(m, "pmac flags\t: %08x\n", mbflags); + + /* find l2 cache info */ + np = find_devices("l2-cache"); + if (np == 0) + np = find_type_devices("cache"); + if (np != 0) { + unsigned int *ic = (unsigned int *) + get_property(np, "i-cache-size", NULL); + unsigned int *dc = (unsigned int *) + get_property(np, "d-cache-size", NULL); + seq_printf(m, "L2 cache\t:"); + has_l2cache = 1; + if (get_property(np, "cache-unified", NULL) != 0 && dc) { + seq_printf(m, " %dK unified", *dc / 1024); + } else { + if (ic) + seq_printf(m, " %dK instruction", *ic / 1024); + if (dc) + seq_printf(m, "%s %dK data", + (ic? " +": ""), *dc / 1024); + } + pp = get_property(np, "ram-type", NULL); + if (pp) + seq_printf(m, " %s", pp); + seq_printf(m, "\n"); + } + + /* find ram info */ + np = find_devices("memory"); + if (np != 0) { + int n; + struct reg_property *reg = (struct reg_property *) + get_property(np, "reg", &n); + + if (reg != 0) { + unsigned long total = 0; + + for (n /= sizeof(struct reg_property); n > 0; --n) + total += (reg++)->size; + seq_printf(m, "memory\t\t: %luMB\n", total >> 20); + } + } + + /* Checks "l2cr-value" property in the registry */ + np = find_devices("cpus"); + if (np == 0) + np = find_type_devices("cpu"); + if (np != 0) { + unsigned int *l2cr = (unsigned int *) + get_property(np, "l2cr-value", NULL); + if (l2cr != 0) { + seq_printf(m, "l2cr override\t: 0x%x\n", *l2cr); + } + } + + /* Indicate newworld/oldworld */ + seq_printf(m, "pmac-generation\t: %s\n", + pmac_newworld ? "NewWorld" : "OldWorld"); + + + return 0; +} + +int __openfirmware +pmac_show_percpuinfo(struct seq_file *m, int i) +{ +#ifdef CONFIG_CPU_FREQ_PMAC + extern unsigned int pmac_get_one_cpufreq(int i); + unsigned int freq = pmac_get_one_cpufreq(i); + if (freq != 0) { + seq_printf(m, "clock\t\t: %dMHz\n", freq/1000); + return 0; + } +#endif /* CONFIG_CPU_FREQ_PMAC */ + return of_show_percpuinfo(m, i); +} + +static volatile u32 *sysctrl_regs; + +void __init +pmac_setup_arch(void) +{ + struct device_node *cpu; + int *fp; + unsigned long pvr; + + pvr = PVR_VER(mfspr(SPRN_PVR)); + + /* Set loops_per_jiffy to a half-way reasonable value, + for use until calibrate_delay gets called. */ + cpu = find_type_devices("cpu"); + if (cpu != 0) { + fp = (int *) get_property(cpu, "clock-frequency", NULL); + if (fp != 0) { + if (pvr == 4 || pvr >= 8) + /* 604, G3, G4 etc. */ + loops_per_jiffy = *fp / HZ; + else + /* 601, 603, etc. */ + loops_per_jiffy = *fp / (2*HZ); + } else + loops_per_jiffy = 50000000 / HZ; + } + + /* this area has the CPU identification register + and some registers used by smp boards */ + sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000); + ohare_init(); + + /* Lookup PCI hosts */ + pmac_find_bridges(); + + /* Checks "l2cr-value" property in the registry */ + if (cpu_has_feature(CPU_FTR_L2CR)) { + struct device_node *np = find_devices("cpus"); + if (np == 0) + np = find_type_devices("cpu"); + if (np != 0) { + unsigned int *l2cr = (unsigned int *) + get_property(np, "l2cr-value", NULL); + if (l2cr != 0) { + ppc_override_l2cr = 1; + ppc_override_l2cr_value = *l2cr; + _set_L2CR(0); + _set_L2CR(ppc_override_l2cr_value); + } + } + } + + if (ppc_override_l2cr) + printk(KERN_INFO "L2CR overriden (0x%x), backside cache is %s\n", + ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000) + ? "enabled" : "disabled"); + +#ifdef CONFIG_KGDB + zs_kgdb_hook(0); +#endif + +#ifdef CONFIG_ADB_CUDA + find_via_cuda(); +#else + if (find_devices("via-cuda")) { + printk("WARNING ! Your machine is Cuda based but your kernel\n"); + printk(" wasn't compiled with CONFIG_ADB_CUDA option !\n"); + } +#endif +#ifdef CONFIG_ADB_PMU + find_via_pmu(); +#else + if (find_devices("via-pmu")) { + printk("WARNING ! Your machine is PMU based but your kernel\n"); + printk(" wasn't compiled with CONFIG_ADB_PMU option !\n"); + } +#endif +#ifdef CONFIG_NVRAM + pmac_nvram_init(); +#endif +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif + ROOT_DEV = DEFAULT_ROOT_DEVICE; + +#ifdef CONFIG_SMP + /* Check for Core99 */ + if (find_devices("uni-n") || find_devices("u3")) + ppc_md.smp_ops = &core99_smp_ops; + else + ppc_md.smp_ops = &psurge_smp_ops; +#endif /* CONFIG_SMP */ + + pci_create_OF_bus_map(); +} + +static void __init ohare_init(void) +{ + /* + * Turn on the L2 cache. + * We assume that we have a PSX memory controller iff + * we have an ohare I/O controller. + */ + if (find_devices("ohare") != NULL) { + if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) { + if (sysctrl_regs[4] & 0x10) + sysctrl_regs[4] |= 0x04000020; + else + sysctrl_regs[4] |= 0x04000000; + if(has_l2cache) + printk(KERN_INFO "Level 2 cache enabled\n"); + } + } +} + +extern char *bootpath; +extern char *bootdevice; +void *boot_host; +int boot_target; +int boot_part; +extern dev_t boot_dev; + +#ifdef CONFIG_SCSI +void __init +note_scsi_host(struct device_node *node, void *host) +{ + int l; + char *p; + + l = strlen(node->full_name); + if (bootpath != NULL && bootdevice != NULL + && strncmp(node->full_name, bootdevice, l) == 0 + && (bootdevice[l] == '/' || bootdevice[l] == 0)) { + boot_host = host; + /* + * There's a bug in OF 1.0.5. (Why am I not surprised.) + * If you pass a path like scsi/sd@1:0 to canon, it returns + * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0 + * That is, the scsi target number doesn't get preserved. + * So we pick the target number out of bootpath and use that. + */ + p = strstr(bootpath, "/sd@"); + if (p != NULL) { + p += 4; + boot_target = simple_strtoul(p, NULL, 10); + p = strchr(p, ':'); + if (p != NULL) + boot_part = simple_strtoul(p + 1, NULL, 10); + } + } +} +#endif + +#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) +static dev_t __init +find_ide_boot(void) +{ + char *p; + int n; + dev_t __init pmac_find_ide_boot(char *bootdevice, int n); + + if (bootdevice == NULL) + return 0; + p = strrchr(bootdevice, '/'); + if (p == NULL) + return 0; + n = p - bootdevice; + + return pmac_find_ide_boot(bootdevice, n); +} +#endif /* CONFIG_BLK_DEV_IDE && CONFIG_BLK_DEV_IDE_PMAC */ + +void __init +find_boot_device(void) +{ +#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) + boot_dev = find_ide_boot(); +#endif +} + +static int initializing = 1; +/* TODO: Merge the suspend-to-ram with the common code !!! + * currently, this is a stub implementation for suspend-to-disk + * only + */ + +#ifdef CONFIG_SOFTWARE_SUSPEND + +static int pmac_pm_prepare(suspend_state_t state) +{ + printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state); + + return 0; +} + +static int pmac_pm_enter(suspend_state_t state) +{ + printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state); + + /* Giveup the lazy FPU & vec so we don't have to back them + * up from the low level code + */ + enable_kernel_fp(); + +#ifdef CONFIG_ALTIVEC + if (cur_cpu_spec[0]->cpu_features & CPU_FTR_ALTIVEC) + enable_kernel_altivec(); +#endif /* CONFIG_ALTIVEC */ + + return 0; +} + +static int pmac_pm_finish(suspend_state_t state) +{ + printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state); + + /* Restore userland MMU context */ + set_context(current->active_mm->context, current->active_mm->pgd); + + return 0; +} + +static struct pm_ops pmac_pm_ops = { + .pm_disk_mode = PM_DISK_SHUTDOWN, + .prepare = pmac_pm_prepare, + .enter = pmac_pm_enter, + .finish = pmac_pm_finish, +}; + +#endif /* CONFIG_SOFTWARE_SUSPEND */ + +static int pmac_late_init(void) +{ + initializing = 0; +#ifdef CONFIG_SOFTWARE_SUSPEND + pm_set_ops(&pmac_pm_ops); +#endif /* CONFIG_SOFTWARE_SUSPEND */ + return 0; +} + +late_initcall(pmac_late_init); + +/* can't be __init - can be called whenever a disk is first accessed */ +void __pmac +note_bootable_part(dev_t dev, int part, int goodness) +{ + static int found_boot = 0; + char *p; + + if (!initializing) + return; + if ((goodness <= current_root_goodness) && + ROOT_DEV != DEFAULT_ROOT_DEVICE) + return; + p = strstr(saved_command_line, "root="); + if (p != NULL && (p == saved_command_line || p[-1] == ' ')) + return; + + if (!found_boot) { + find_boot_device(); + found_boot = 1; + } + if (!boot_dev || dev == boot_dev) { + ROOT_DEV = dev + part; + boot_dev = 0; + current_root_goodness = goodness; + } +} + +void __pmac +pmac_restart(char *cmd) +{ +#ifdef CONFIG_ADB_CUDA + struct adb_request req; +#endif /* CONFIG_ADB_CUDA */ + + switch (sys_ctrler) { +#ifdef CONFIG_ADB_CUDA + case SYS_CTRLER_CUDA: + cuda_request(&req, NULL, 2, CUDA_PACKET, + CUDA_RESET_SYSTEM); + for (;;) + cuda_poll(); + break; +#endif /* CONFIG_ADB_CUDA */ +#ifdef CONFIG_ADB_PMU + case SYS_CTRLER_PMU: + pmu_restart(); + break; +#endif /* CONFIG_ADB_PMU */ + default: ; + } +} + +void __pmac +pmac_power_off(void) +{ +#ifdef CONFIG_ADB_CUDA + struct adb_request req; +#endif /* CONFIG_ADB_CUDA */ + + switch (sys_ctrler) { +#ifdef CONFIG_ADB_CUDA + case SYS_CTRLER_CUDA: + cuda_request(&req, NULL, 2, CUDA_PACKET, + CUDA_POWERDOWN); + for (;;) + cuda_poll(); + break; +#endif /* CONFIG_ADB_CUDA */ +#ifdef CONFIG_ADB_PMU + case SYS_CTRLER_PMU: + pmu_shutdown(); + break; +#endif /* CONFIG_ADB_PMU */ + default: ; + } +} + +void __pmac +pmac_halt(void) +{ + pmac_power_off(); +} + +/* + * Read in a property describing some pieces of memory. + */ + +static int __init +get_mem_prop(char *name, struct mem_pieces *mp) +{ + struct reg_property *rp; + int i, s; + unsigned int *ip; + int nac = prom_n_addr_cells(memory_node); + int nsc = prom_n_size_cells(memory_node); + + ip = (unsigned int *) get_property(memory_node, name, &s); + if (ip == NULL) { + printk(KERN_ERR "error: couldn't get %s property on /memory\n", + name); + return 0; + } + s /= (nsc + nac) * 4; + rp = mp->regions; + for (i = 0; i < s; ++i, ip += nac+nsc) { + if (nac >= 2 && ip[nac-2] != 0) + continue; + rp->address = ip[nac-1]; + if (nsc >= 2 && ip[nac+nsc-2] != 0) + rp->size = ~0U; + else + rp->size = ip[nac+nsc-1]; + ++rp; + } + mp->n_regions = rp - mp->regions; + + /* Make sure the pieces are sorted. */ + mem_pieces_sort(mp); + mem_pieces_coalesce(mp); + return 1; +} + +/* + * On systems with Open Firmware, collect information about + * physical RAM and which pieces are already in use. + * At this point, we have (at least) the first 8MB mapped with a BAT. + * Our text, data, bss use something over 1MB, starting at 0. + * Open Firmware may be using 1MB at the 4MB point. + */ +unsigned long __init +pmac_find_end_of_memory(void) +{ + unsigned long a, total; + struct mem_pieces phys_mem; + + /* + * Find out where physical memory is, and check that it + * starts at 0 and is contiguous. It seems that RAM is + * always physically contiguous on Power Macintoshes. + * + * Supporting discontiguous physical memory isn't hard, + * it just makes the virtual <-> physical mapping functions + * more complicated (or else you end up wasting space + * in mem_map). + */ + memory_node = find_devices("memory"); + if (memory_node == NULL || !get_mem_prop("reg", &phys_mem) + || phys_mem.n_regions == 0) + panic("No RAM??"); + a = phys_mem.regions[0].address; + if (a != 0) + panic("RAM doesn't start at physical address 0"); + total = phys_mem.regions[0].size; + + if (phys_mem.n_regions > 1) { + printk("RAM starting at 0x%x is not contiguous\n", + phys_mem.regions[1].address); + printk("Using RAM from 0 to 0x%lx\n", total-1); + } + + return total; +} + +void __init +pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + /* isa_io_base gets set in pmac_find_bridges */ + isa_mem_base = PMAC_ISA_MEM_BASE; + pci_dram_offset = PMAC_PCI_DRAM_OFFSET; + ISA_DMA_THRESHOLD = ~0L; + DMA_MODE_READ = 1; + DMA_MODE_WRITE = 2; + + ppc_md.setup_arch = pmac_setup_arch; + ppc_md.show_cpuinfo = pmac_show_cpuinfo; + ppc_md.show_percpuinfo = pmac_show_percpuinfo; + ppc_md.irq_canonicalize = NULL; + ppc_md.init_IRQ = pmac_pic_init; + ppc_md.get_irq = pmac_get_irq; /* Changed later on ... */ + + ppc_md.pcibios_fixup = pmac_pcibios_fixup; + ppc_md.pcibios_enable_device_hook = pmac_pci_enable_device_hook; + ppc_md.pcibios_after_init = pmac_pcibios_after_init; + ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot; + + ppc_md.restart = pmac_restart; + ppc_md.power_off = pmac_power_off; + ppc_md.halt = pmac_halt; + + ppc_md.time_init = pmac_time_init; + ppc_md.set_rtc_time = pmac_set_rtc_time; + ppc_md.get_rtc_time = pmac_get_rtc_time; + ppc_md.calibrate_decr = pmac_calibrate_decr; + + ppc_md.find_end_of_memory = pmac_find_end_of_memory; + + ppc_md.feature_call = pmac_do_feature_call; + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +#ifdef CONFIG_BLK_DEV_IDE_PMAC + ppc_ide_md.ide_init_hwif = pmac_ide_init_hwif_ports; + ppc_ide_md.default_io_base = pmac_ide_get_base; +#endif /* CONFIG_BLK_DEV_IDE_PMAC */ +#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */ + +#ifdef CONFIG_BOOTX_TEXT + ppc_md.progress = pmac_progress; +#endif /* CONFIG_BOOTX_TEXT */ + + if (ppc_md.progress) ppc_md.progress("pmac_init(): exit", 0); + +} + +#ifdef CONFIG_BOOTX_TEXT +void __init +pmac_progress(char *s, unsigned short hex) +{ + if (boot_text_mapped) { + btext_drawstring(s); + btext_drawchar('\n'); + } +} +#endif /* CONFIG_BOOTX_TEXT */ + +static int __init +pmac_declare_of_platform_devices(void) +{ + struct device_node *np; + + np = find_devices("uni-n"); + if (np) { + for (np = np->child; np != NULL; np = np->sibling) + if (strncmp(np->name, "i2c", 3) == 0) { + of_platform_device_create(np, "uni-n-i2c"); + break; + } + } + np = find_devices("u3"); + if (np) { + for (np = np->child; np != NULL; np = np->sibling) + if (strncmp(np->name, "i2c", 3) == 0) { + of_platform_device_create(np, "u3-i2c"); + break; + } + } + + np = find_devices("valkyrie"); + if (np) + of_platform_device_create(np, "valkyrie"); + np = find_devices("platinum"); + if (np) + of_platform_device_create(np, "platinum"); + + return 0; +} + +device_initcall(pmac_declare_of_platform_devices); diff --git a/arch/ppc/platforms/pmac_sleep.S b/arch/ppc/platforms/pmac_sleep.S new file mode 100644 index 00000000000..3139b6766ad --- /dev/null +++ b/arch/ppc/platforms/pmac_sleep.S @@ -0,0 +1,390 @@ +/* + * This file contains sleep low-level functions for PowerBook G3. + * Copyright (C) 1999 Benjamin Herrenschmidt (benh@kernel.crashing.org) + * and Paul Mackerras (paulus@samba.org). + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include <linux/config.h> +#include <asm/processor.h> +#include <asm/page.h> +#include <asm/ppc_asm.h> +#include <asm/cputable.h> +#include <asm/cache.h> +#include <asm/thread_info.h> +#include <asm/offsets.h> + +#define MAGIC 0x4c617273 /* 'Lars' */ + +/* + * Structure for storing CPU registers on the stack. + */ +#define SL_SP 0 +#define SL_PC 4 +#define SL_MSR 8 +#define SL_SDR1 0xc +#define SL_SPRG0 0x10 /* 4 sprg's */ +#define SL_DBAT0 0x20 +#define SL_IBAT0 0x28 +#define SL_DBAT1 0x30 +#define SL_IBAT1 0x38 +#define SL_DBAT2 0x40 +#define SL_IBAT2 0x48 +#define SL_DBAT3 0x50 +#define SL_IBAT3 0x58 +#define SL_TB 0x60 +#define SL_R2 0x68 +#define SL_CR 0x6c +#define SL_R12 0x70 /* r12 to r31 */ +#define SL_SIZE (SL_R12 + 80) + + .section .text + .align 5 + +#if defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_CPU_FREQ_PMAC) + +/* This gets called by via-pmu.c late during the sleep process. + * The PMU was already send the sleep command and will shut us down + * soon. We need to save all that is needed and setup the wakeup + * vector that will be called by the ROM on wakeup + */ +_GLOBAL(low_sleep_handler) +#ifndef CONFIG_6xx + blr +#else + mflr r0 + stw r0,4(r1) + stwu r1,-SL_SIZE(r1) + mfcr r0 + stw r0,SL_CR(r1) + stw r2,SL_R2(r1) + stmw r12,SL_R12(r1) + + /* Save MSR & SDR1 */ + mfmsr r4 + stw r4,SL_MSR(r1) + mfsdr1 r4 + stw r4,SL_SDR1(r1) + + /* Get a stable timebase and save it */ +1: mftbu r4 + stw r4,SL_TB(r1) + mftb r5 + stw r5,SL_TB+4(r1) + mftbu r3 + cmpw r3,r4 + bne 1b + + /* Save SPRGs */ + mfsprg r4,0 + stw r4,SL_SPRG0(r1) + mfsprg r4,1 + stw r4,SL_SPRG0+4(r1) + mfsprg r4,2 + stw r4,SL_SPRG0+8(r1) + mfsprg r4,3 + stw r4,SL_SPRG0+12(r1) + + /* Save BATs */ + mfdbatu r4,0 + stw r4,SL_DBAT0(r1) + mfdbatl r4,0 + stw r4,SL_DBAT0+4(r1) + mfdbatu r4,1 + stw r4,SL_DBAT1(r1) + mfdbatl r4,1 + stw r4,SL_DBAT1+4(r1) + mfdbatu r4,2 + stw r4,SL_DBAT2(r1) + mfdbatl r4,2 + stw r4,SL_DBAT2+4(r1) + mfdbatu r4,3 + stw r4,SL_DBAT3(r1) + mfdbatl r4,3 + stw r4,SL_DBAT3+4(r1) + mfibatu r4,0 + stw r4,SL_IBAT0(r1) + mfibatl r4,0 + stw r4,SL_IBAT0+4(r1) + mfibatu r4,1 + stw r4,SL_IBAT1(r1) + mfibatl r4,1 + stw r4,SL_IBAT1+4(r1) + mfibatu r4,2 + stw r4,SL_IBAT2(r1) + mfibatl r4,2 + stw r4,SL_IBAT2+4(r1) + mfibatu r4,3 + stw r4,SL_IBAT3(r1) + mfibatl r4,3 + stw r4,SL_IBAT3+4(r1) + + /* Backup various CPU config stuffs */ + bl __save_cpu_setup + + /* The ROM can wake us up via 2 different vectors: + * - On wallstreet & lombard, we must write a magic + * value 'Lars' at address 4 and a pointer to a + * memory location containing the PC to resume from + * at address 0. + * - On Core99, we must store the wakeup vector at + * address 0x80 and eventually it's parameters + * at address 0x84. I've have some trouble with those + * parameters however and I no longer use them. + */ + lis r5,grackle_wake_up@ha + addi r5,r5,grackle_wake_up@l + tophys(r5,r5) + stw r5,SL_PC(r1) + lis r4,KERNELBASE@h + tophys(r5,r1) + addi r5,r5,SL_PC + lis r6,MAGIC@ha + addi r6,r6,MAGIC@l + stw r5,0(r4) + stw r6,4(r4) + /* Setup stuffs at 0x80-0x84 for Core99 */ + lis r3,core99_wake_up@ha + addi r3,r3,core99_wake_up@l + tophys(r3,r3) + stw r3,0x80(r4) + stw r5,0x84(r4) + /* Store a pointer to our backup storage into + * a kernel global + */ + lis r3,sleep_storage@ha + addi r3,r3,sleep_storage@l + stw r5,0(r3) + + /* Flush & disable all caches */ + bl flush_disable_caches + + /* Turn off data relocation. */ + mfmsr r3 /* Save MSR in r7 */ + rlwinm r3,r3,0,28,26 /* Turn off DR bit */ + sync + mtmsr r3 + isync + +BEGIN_FTR_SECTION + /* Flush any pending L2 data prefetches to work around HW bug */ + sync + lis r3,0xfff0 + lwz r0,0(r3) /* perform cache-inhibited load to ROM */ + sync /* (caches are disabled at this point) */ +END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450) + +/* + * Set the HID0 and MSR for sleep. + */ + mfspr r2,SPRN_HID0 + rlwinm r2,r2,0,10,7 /* clear doze, nap */ + oris r2,r2,HID0_SLEEP@h + sync + isync + mtspr SPRN_HID0,r2 + sync + +/* This loop puts us back to sleep in case we have a spurrious + * wakeup so that the host bridge properly stays asleep. The + * CPU will be turned off, either after a known time (about 1 + * second) on wallstreet & lombard, or as soon as the CPU enters + * SLEEP mode on core99 + */ + mfmsr r2 + oris r2,r2,MSR_POW@h +1: sync + mtmsr r2 + isync + b 1b + +/* + * Here is the resume code. + */ + + +/* + * Core99 machines resume here + * r4 has the physical address of SL_PC(sp) (unused) + */ +_GLOBAL(core99_wake_up) + /* Make sure HID0 no longer contains any sleep bit and that data cache + * is disabled + */ + mfspr r3,SPRN_HID0 + rlwinm r3,r3,0,11,7 /* clear SLEEP, NAP, DOZE bits */ + rlwinm 3,r3,0,18,15 /* clear DCE, ICE */ + mtspr SPRN_HID0,r3 + sync + isync + + /* sanitize MSR */ + mfmsr r3 + ori r3,r3,MSR_EE|MSR_IP + xori r3,r3,MSR_EE|MSR_IP + sync + isync + mtmsr r3 + sync + isync + + /* Recover sleep storage */ + lis r3,sleep_storage@ha + addi r3,r3,sleep_storage@l + tophys(r3,r3) + lwz r1,0(r3) + + /* Pass thru to older resume code ... */ +/* + * Here is the resume code for older machines. + * r1 has the physical address of SL_PC(sp). + */ + +grackle_wake_up: + + /* Restore the kernel's segment registers before + * we do any r1 memory access as we are not sure they + * are in a sane state above the first 256Mb region + */ + li r0,16 /* load up segment register values */ + mtctr r0 /* for context 0 */ + lis r3,0x2000 /* Ku = 1, VSID = 0 */ + li r4,0 +3: mtsrin r3,r4 + addi r3,r3,0x111 /* increment VSID */ + addis r4,r4,0x1000 /* address of next segment */ + bdnz 3b + sync + isync + + subi r1,r1,SL_PC + + /* Restore various CPU config stuffs */ + bl __restore_cpu_setup + + /* Invalidate & enable L1 cache, we don't care about + * whatever the ROM may have tried to write to memory + */ + bl __inval_enable_L1 + + /* Restore the BATs, and SDR1. Then we can turn on the MMU. */ + lwz r4,SL_SDR1(r1) + mtsdr1 r4 + lwz r4,SL_SPRG0(r1) + mtsprg 0,r4 + lwz r4,SL_SPRG0+4(r1) + mtsprg 1,r4 + lwz r4,SL_SPRG0+8(r1) + mtsprg 2,r4 + lwz r4,SL_SPRG0+12(r1) + mtsprg 3,r4 + + lwz r4,SL_DBAT0(r1) + mtdbatu 0,r4 + lwz r4,SL_DBAT0+4(r1) + mtdbatl 0,r4 + lwz r4,SL_DBAT1(r1) + mtdbatu 1,r4 + lwz r4,SL_DBAT1+4(r1) + mtdbatl 1,r4 + lwz r4,SL_DBAT2(r1) + mtdbatu 2,r4 + lwz r4,SL_DBAT2+4(r1) + mtdbatl 2,r4 + lwz r4,SL_DBAT3(r1) + mtdbatu 3,r4 + lwz r4,SL_DBAT3+4(r1) + mtdbatl 3,r4 + lwz r4,SL_IBAT0(r1) + mtibatu 0,r4 + lwz r4,SL_IBAT0+4(r1) + mtibatl 0,r4 + lwz r4,SL_IBAT1(r1) + mtibatu 1,r4 + lwz r4,SL_IBAT1+4(r1) + mtibatl 1,r4 + lwz r4,SL_IBAT2(r1) + mtibatu 2,r4 + lwz r4,SL_IBAT2+4(r1) + mtibatl 2,r4 + lwz r4,SL_IBAT3(r1) + mtibatu 3,r4 + lwz r4,SL_IBAT3+4(r1) + mtibatl 3,r4 + +BEGIN_FTR_SECTION + li r4,0 + mtspr SPRN_DBAT4U,r4 + mtspr SPRN_DBAT4L,r4 + mtspr SPRN_DBAT5U,r4 + mtspr SPRN_DBAT5L,r4 + mtspr SPRN_DBAT6U,r4 + mtspr SPRN_DBAT6L,r4 + mtspr SPRN_DBAT7U,r4 + mtspr SPRN_DBAT7L,r4 + mtspr SPRN_IBAT4U,r4 + mtspr SPRN_IBAT4L,r4 + mtspr SPRN_IBAT5U,r4 + mtspr SPRN_IBAT5L,r4 + mtspr SPRN_IBAT6U,r4 + mtspr SPRN_IBAT6L,r4 + mtspr SPRN_IBAT7U,r4 + mtspr SPRN_IBAT7L,r4 +END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS) + + /* Flush all TLBs */ + lis r4,0x1000 +1: addic. r4,r4,-0x1000 + tlbie r4 + blt 1b + sync + + /* restore the MSR and turn on the MMU */ + lwz r3,SL_MSR(r1) + bl turn_on_mmu + + /* get back the stack pointer */ + tovirt(r1,r1) + + /* Restore TB */ + li r3,0 + mttbl r3 + lwz r3,SL_TB(r1) + lwz r4,SL_TB+4(r1) + mttbu r3 + mttbl r4 + + /* Restore the callee-saved registers and return */ + lwz r0,SL_CR(r1) + mtcr r0 + lwz r2,SL_R2(r1) + lmw r12,SL_R12(r1) + addi r1,r1,SL_SIZE + lwz r0,4(r1) + mtlr r0 + blr + +turn_on_mmu: + mflr r4 + tovirt(r4,r4) + mtsrr0 r4 + mtsrr1 r3 + sync + isync + rfi + +#endif /* defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_CPU_FREQ) */ + + .section .data + .balign L1_CACHE_LINE_SIZE +sleep_storage: + .long 0 + .balign L1_CACHE_LINE_SIZE, 0 + +#endif /* CONFIG_6xx */ + .section .text diff --git a/arch/ppc/platforms/pmac_smp.c b/arch/ppc/platforms/pmac_smp.c new file mode 100644 index 00000000000..2b88745576a --- /dev/null +++ b/arch/ppc/platforms/pmac_smp.c @@ -0,0 +1,640 @@ +/* + * SMP support for power macintosh. + * + * We support both the old "powersurge" SMP architecture + * and the current Core99 (G4 PowerMac) machines. + * + * Note that we don't support the very first rev. of + * Apple/DayStar 2 CPUs board, the one with the funky + * watchdog. Hopefully, none of these should be there except + * maybe internally to Apple. I should probably still add some + * code to detect this card though and disable SMP. --BenH. + * + * Support Macintosh G4 SMP by Troy Benjegerdes (hozer@drgw.net) + * and Ben Herrenschmidt <benh@kernel.crashing.org>. + * + * Support for DayStar quad CPU cards + * Copyright (C) XLR8, Inc. 1994-2000 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/interrupt.h> +#include <linux/kernel_stat.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/errno.h> +#include <linux/hardirq.h> + +#include <asm/ptrace.h> +#include <asm/atomic.h> +#include <asm/irq.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/sections.h> +#include <asm/io.h> +#include <asm/prom.h> +#include <asm/smp.h> +#include <asm/residual.h> +#include <asm/machdep.h> +#include <asm/pmac_feature.h> +#include <asm/time.h> +#include <asm/open_pic.h> +#include <asm/cacheflush.h> +#include <asm/keylargo.h> + +/* + * Powersurge (old powermac SMP) support. + */ + +extern void __secondary_start_psurge(void); +extern void __secondary_start_psurge2(void); /* Temporary horrible hack */ +extern void __secondary_start_psurge3(void); /* Temporary horrible hack */ + +/* Addresses for powersurge registers */ +#define HAMMERHEAD_BASE 0xf8000000 +#define HHEAD_CONFIG 0x90 +#define HHEAD_SEC_INTR 0xc0 + +/* register for interrupting the primary processor on the powersurge */ +/* N.B. this is actually the ethernet ROM! */ +#define PSURGE_PRI_INTR 0xf3019000 + +/* register for storing the start address for the secondary processor */ +/* N.B. this is the PCI config space address register for the 1st bridge */ +#define PSURGE_START 0xf2800000 + +/* Daystar/XLR8 4-CPU card */ +#define PSURGE_QUAD_REG_ADDR 0xf8800000 + +#define PSURGE_QUAD_IRQ_SET 0 +#define PSURGE_QUAD_IRQ_CLR 1 +#define PSURGE_QUAD_IRQ_PRIMARY 2 +#define PSURGE_QUAD_CKSTOP_CTL 3 +#define PSURGE_QUAD_PRIMARY_ARB 4 +#define PSURGE_QUAD_BOARD_ID 6 +#define PSURGE_QUAD_WHICH_CPU 7 +#define PSURGE_QUAD_CKSTOP_RDBK 8 +#define PSURGE_QUAD_RESET_CTL 11 + +#define PSURGE_QUAD_OUT(r, v) (out_8(quad_base + ((r) << 4) + 4, (v))) +#define PSURGE_QUAD_IN(r) (in_8(quad_base + ((r) << 4) + 4) & 0x0f) +#define PSURGE_QUAD_BIS(r, v) (PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) | (v))) +#define PSURGE_QUAD_BIC(r, v) (PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) & ~(v))) + +/* virtual addresses for the above */ +static volatile u8 *hhead_base; +static volatile u8 *quad_base; +static volatile u32 *psurge_pri_intr; +static volatile u8 *psurge_sec_intr; +static volatile u32 *psurge_start; + +/* values for psurge_type */ +#define PSURGE_NONE -1 +#define PSURGE_DUAL 0 +#define PSURGE_QUAD_OKEE 1 +#define PSURGE_QUAD_COTTON 2 +#define PSURGE_QUAD_ICEGRASS 3 + +/* what sort of powersurge board we have */ +static int psurge_type = PSURGE_NONE; + +/* L2 and L3 cache settings to pass from CPU0 to CPU1 */ +volatile static long int core99_l2_cache; +volatile static long int core99_l3_cache; + +/* Timebase freeze GPIO */ +static unsigned int core99_tb_gpio; + +/* Sync flag for HW tb sync */ +static volatile int sec_tb_reset = 0; + +static void __init core99_init_caches(int cpu) +{ + if (!cpu_has_feature(CPU_FTR_L2CR)) + return; + + if (cpu == 0) { + core99_l2_cache = _get_L2CR(); + printk("CPU0: L2CR is %lx\n", core99_l2_cache); + } else { + printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR()); + _set_L2CR(0); + _set_L2CR(core99_l2_cache); + printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache); + } + + if (!cpu_has_feature(CPU_FTR_L3CR)) + return; + + if (cpu == 0){ + core99_l3_cache = _get_L3CR(); + printk("CPU0: L3CR is %lx\n", core99_l3_cache); + } else { + printk("CPU%d: L3CR was %lx\n", cpu, _get_L3CR()); + _set_L3CR(0); + _set_L3CR(core99_l3_cache); + printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache); + } +} + +/* + * Set and clear IPIs for powersurge. + */ +static inline void psurge_set_ipi(int cpu) +{ + if (psurge_type == PSURGE_NONE) + return; + if (cpu == 0) + in_be32(psurge_pri_intr); + else if (psurge_type == PSURGE_DUAL) + out_8(psurge_sec_intr, 0); + else + PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_SET, 1 << cpu); +} + +static inline void psurge_clr_ipi(int cpu) +{ + if (cpu > 0) { + switch(psurge_type) { + case PSURGE_DUAL: + out_8(psurge_sec_intr, ~0); + case PSURGE_NONE: + break; + default: + PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, 1 << cpu); + } + } +} + +/* + * On powersurge (old SMP powermac architecture) we don't have + * separate IPIs for separate messages like openpic does. Instead + * we have a bitmap for each processor, where a 1 bit means that + * the corresponding message is pending for that processor. + * Ideally each cpu's entry would be in a different cache line. + * -- paulus. + */ +static unsigned long psurge_smp_message[NR_CPUS]; + +void __pmac psurge_smp_message_recv(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + int msg; + + /* clear interrupt */ + psurge_clr_ipi(cpu); + + if (num_online_cpus() < 2) + return; + + /* make sure there is a message there */ + for (msg = 0; msg < 4; msg++) + if (test_and_clear_bit(msg, &psurge_smp_message[cpu])) + smp_message_recv(msg, regs); +} + +irqreturn_t __pmac psurge_primary_intr(int irq, void *d, struct pt_regs *regs) +{ + psurge_smp_message_recv(regs); + return IRQ_HANDLED; +} + +static void __pmac smp_psurge_message_pass(int target, int msg, unsigned long data, + int wait) +{ + int i; + + if (num_online_cpus() < 2) + return; + + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; + if (target == MSG_ALL + || (target == MSG_ALL_BUT_SELF && i != smp_processor_id()) + || target == i) { + set_bit(msg, &psurge_smp_message[i]); + psurge_set_ipi(i); + } + } +} + +/* + * Determine a quad card presence. We read the board ID register, we + * force the data bus to change to something else, and we read it again. + * It it's stable, then the register probably exist (ugh !) + */ +static int __init psurge_quad_probe(void) +{ + int type; + unsigned int i; + + type = PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID); + if (type < PSURGE_QUAD_OKEE || type > PSURGE_QUAD_ICEGRASS + || type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID)) + return PSURGE_DUAL; + + /* looks OK, try a slightly more rigorous test */ + /* bogus is not necessarily cacheline-aligned, + though I don't suppose that really matters. -- paulus */ + for (i = 0; i < 100; i++) { + volatile u32 bogus[8]; + bogus[(0+i)%8] = 0x00000000; + bogus[(1+i)%8] = 0x55555555; + bogus[(2+i)%8] = 0xFFFFFFFF; + bogus[(3+i)%8] = 0xAAAAAAAA; + bogus[(4+i)%8] = 0x33333333; + bogus[(5+i)%8] = 0xCCCCCCCC; + bogus[(6+i)%8] = 0xCCCCCCCC; + bogus[(7+i)%8] = 0x33333333; + wmb(); + asm volatile("dcbf 0,%0" : : "r" (bogus) : "memory"); + mb(); + if (type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID)) + return PSURGE_DUAL; + } + return type; +} + +static void __init psurge_quad_init(void) +{ + int procbits; + + if (ppc_md.progress) ppc_md.progress("psurge_quad_init", 0x351); + procbits = ~PSURGE_QUAD_IN(PSURGE_QUAD_WHICH_CPU); + if (psurge_type == PSURGE_QUAD_ICEGRASS) + PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits); + else + PSURGE_QUAD_BIC(PSURGE_QUAD_CKSTOP_CTL, procbits); + mdelay(33); + out_8(psurge_sec_intr, ~0); + PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, procbits); + PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits); + if (psurge_type != PSURGE_QUAD_ICEGRASS) + PSURGE_QUAD_BIS(PSURGE_QUAD_CKSTOP_CTL, procbits); + PSURGE_QUAD_BIC(PSURGE_QUAD_PRIMARY_ARB, procbits); + mdelay(33); + PSURGE_QUAD_BIC(PSURGE_QUAD_RESET_CTL, procbits); + mdelay(33); + PSURGE_QUAD_BIS(PSURGE_QUAD_PRIMARY_ARB, procbits); + mdelay(33); +} + +static int __init smp_psurge_probe(void) +{ + int i, ncpus; + + /* We don't do SMP on the PPC601 -- paulus */ + if (PVR_VER(mfspr(SPRN_PVR)) == 1) + return 1; + + /* + * The powersurge cpu board can be used in the generation + * of powermacs that have a socket for an upgradeable cpu card, + * including the 7500, 8500, 9500, 9600. + * The device tree doesn't tell you if you have 2 cpus because + * OF doesn't know anything about the 2nd processor. + * Instead we look for magic bits in magic registers, + * in the hammerhead memory controller in the case of the + * dual-cpu powersurge board. -- paulus. + */ + if (find_devices("hammerhead") == NULL) + return 1; + + hhead_base = ioremap(HAMMERHEAD_BASE, 0x800); + quad_base = ioremap(PSURGE_QUAD_REG_ADDR, 1024); + psurge_sec_intr = hhead_base + HHEAD_SEC_INTR; + + psurge_type = psurge_quad_probe(); + if (psurge_type != PSURGE_DUAL) { + psurge_quad_init(); + /* All released cards using this HW design have 4 CPUs */ + ncpus = 4; + } else { + iounmap((void *) quad_base); + if ((in_8(hhead_base + HHEAD_CONFIG) & 0x02) == 0) { + /* not a dual-cpu card */ + iounmap((void *) hhead_base); + psurge_type = PSURGE_NONE; + return 1; + } + ncpus = 2; + } + + psurge_start = ioremap(PSURGE_START, 4); + psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4); + + /* this is not actually strictly necessary -- paulus. */ + for (i = 1; i < ncpus; ++i) + smp_hw_index[i] = i; + + if (ppc_md.progress) ppc_md.progress("smp_psurge_probe - done", 0x352); + + return ncpus; +} + +static void __init smp_psurge_kick_cpu(int nr) +{ + void (*start)(void) = __secondary_start_psurge; + unsigned long a; + + /* may need to flush here if secondary bats aren't setup */ + for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32) + asm volatile("dcbf 0,%0" : : "r" (a) : "memory"); + asm volatile("sync"); + + if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu", 0x353); + + /* setup entry point of secondary processor */ + switch (nr) { + case 2: + start = __secondary_start_psurge2; + break; + case 3: + start = __secondary_start_psurge3; + break; + } + + out_be32(psurge_start, __pa(start)); + mb(); + + psurge_set_ipi(nr); + udelay(10); + psurge_clr_ipi(nr); + + if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354); +} + +/* + * With the dual-cpu powersurge board, the decrementers and timebases + * of both cpus are frozen after the secondary cpu is started up, + * until we give the secondary cpu another interrupt. This routine + * uses this to get the timebases synchronized. + * -- paulus. + */ +static void __init psurge_dual_sync_tb(int cpu_nr) +{ + int t; + + set_dec(tb_ticks_per_jiffy); + set_tb(0, 0); + last_jiffy_stamp(cpu_nr) = 0; + + if (cpu_nr > 0) { + mb(); + sec_tb_reset = 1; + return; + } + + /* wait for the secondary to have reset its TB before proceeding */ + for (t = 10000000; t > 0 && !sec_tb_reset; --t) + ; + + /* now interrupt the secondary, starting both TBs */ + psurge_set_ipi(1); + + smp_tb_synchronized = 1; +} + +static struct irqaction psurge_irqaction = { + .handler = psurge_primary_intr, + .flags = SA_INTERRUPT, + .mask = CPU_MASK_NONE, + .name = "primary IPI", +}; + +static void __init smp_psurge_setup_cpu(int cpu_nr) +{ + + if (cpu_nr == 0) { + /* If we failed to start the second CPU, we should still + * send it an IPI to start the timebase & DEC or we might + * have them stuck. + */ + if (num_online_cpus() < 2) { + if (psurge_type == PSURGE_DUAL) + psurge_set_ipi(1); + return; + } + /* reset the entry point so if we get another intr we won't + * try to startup again */ + out_be32(psurge_start, 0x100); + if (setup_irq(30, &psurge_irqaction)) + printk(KERN_ERR "Couldn't get primary IPI interrupt"); + } + + if (psurge_type == PSURGE_DUAL) + psurge_dual_sync_tb(cpu_nr); +} + +void __init smp_psurge_take_timebase(void) +{ + /* Dummy implementation */ +} + +void __init smp_psurge_give_timebase(void) +{ + /* Dummy implementation */ +} + +static int __init smp_core99_probe(void) +{ +#ifdef CONFIG_6xx + extern int powersave_nap; +#endif + struct device_node *cpus, *firstcpu; + int i, ncpus = 0, boot_cpu = -1; + u32 *tbprop; + + if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345); + cpus = firstcpu = find_type_devices("cpu"); + while(cpus != NULL) { + u32 *regprop = (u32 *)get_property(cpus, "reg", NULL); + char *stateprop = (char *)get_property(cpus, "state", NULL); + if (regprop != NULL && stateprop != NULL && + !strncmp(stateprop, "running", 7)) + boot_cpu = *regprop; + ++ncpus; + cpus = cpus->next; + } + if (boot_cpu == -1) + printk(KERN_WARNING "Couldn't detect boot CPU !\n"); + if (boot_cpu != 0) + printk(KERN_WARNING "Boot CPU is %d, unsupported setup !\n", boot_cpu); + + if (machine_is_compatible("MacRISC4")) { + extern struct smp_ops_t core99_smp_ops; + + core99_smp_ops.take_timebase = smp_generic_take_timebase; + core99_smp_ops.give_timebase = smp_generic_give_timebase; + } else { + if (firstcpu != NULL) + tbprop = (u32 *)get_property(firstcpu, "timebase-enable", NULL); + if (tbprop) + core99_tb_gpio = *tbprop; + else + core99_tb_gpio = KL_GPIO_TB_ENABLE; + } + + if (ncpus > 1) { + openpic_request_IPIs(); + for (i = 1; i < ncpus; ++i) + smp_hw_index[i] = i; +#ifdef CONFIG_6xx + powersave_nap = 0; +#endif + core99_init_caches(0); + } + + return ncpus; +} + +static void __init smp_core99_kick_cpu(int nr) +{ + unsigned long save_vector, new_vector; + unsigned long flags; + + volatile unsigned long *vector + = ((volatile unsigned long *)(KERNELBASE+0x100)); + if (nr < 1 || nr > 3) + return; + if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346); + + local_irq_save(flags); + local_irq_disable(); + + /* Save reset vector */ + save_vector = *vector; + + /* Setup fake reset vector that does + * b __secondary_start_psurge - KERNELBASE + */ + switch(nr) { + case 1: + new_vector = (unsigned long)__secondary_start_psurge; + break; + case 2: + new_vector = (unsigned long)__secondary_start_psurge2; + break; + case 3: + new_vector = (unsigned long)__secondary_start_psurge3; + break; + } + *vector = 0x48000002 + new_vector - KERNELBASE; + + /* flush data cache and inval instruction cache */ + flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); + + /* Put some life in our friend */ + pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0); + + /* FIXME: We wait a bit for the CPU to take the exception, I should + * instead wait for the entry code to set something for me. Well, + * ideally, all that crap will be done in prom.c and the CPU left + * in a RAM-based wait loop like CHRP. + */ + mdelay(1); + + /* Restore our exception vector */ + *vector = save_vector; + flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); + + local_irq_restore(flags); + if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347); +} + +static void __init smp_core99_setup_cpu(int cpu_nr) +{ + /* Setup L2/L3 */ + if (cpu_nr != 0) + core99_init_caches(cpu_nr); + + /* Setup openpic */ + do_openpic_setup_cpu(); + + if (cpu_nr == 0) { +#ifdef CONFIG_POWER4 + extern void g5_phy_disable_cpu1(void); + + /* If we didn't start the second CPU, we must take + * it off the bus + */ + if (machine_is_compatible("MacRISC4") && + num_online_cpus() < 2) + g5_phy_disable_cpu1(); +#endif /* CONFIG_POWER4 */ + if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349); + } +} + +void __init smp_core99_take_timebase(void) +{ + /* Secondary processor "takes" the timebase by freezing + * it, resetting its local TB and telling CPU 0 to go on + */ + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4); + pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0); + mb(); + + set_dec(tb_ticks_per_jiffy); + set_tb(0, 0); + last_jiffy_stamp(smp_processor_id()) = 0; + + mb(); + sec_tb_reset = 1; +} + +void __init smp_core99_give_timebase(void) +{ + unsigned int t; + + /* Primary processor waits for secondary to have frozen + * the timebase, resets local TB, and kick timebase again + */ + /* wait for the secondary to have reset its TB before proceeding */ + for (t = 1000; t > 0 && !sec_tb_reset; --t) + udelay(1000); + if (t == 0) + printk(KERN_WARNING "Timeout waiting sync on second CPU\n"); + + set_dec(tb_ticks_per_jiffy); + set_tb(0, 0); + last_jiffy_stamp(smp_processor_id()) = 0; + mb(); + + /* Now, restart the timebase by leaving the GPIO to an open collector */ + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0); + pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0); + + smp_tb_synchronized = 1; +} + + +/* PowerSurge-style Macs */ +struct smp_ops_t psurge_smp_ops __pmacdata = { + .message_pass = smp_psurge_message_pass, + .probe = smp_psurge_probe, + .kick_cpu = smp_psurge_kick_cpu, + .setup_cpu = smp_psurge_setup_cpu, + .give_timebase = smp_psurge_give_timebase, + .take_timebase = smp_psurge_take_timebase, +}; + +/* Core99 Macs (dual G4s) */ +struct smp_ops_t core99_smp_ops __pmacdata = { + .message_pass = smp_openpic_message_pass, + .probe = smp_core99_probe, + .kick_cpu = smp_core99_kick_cpu, + .setup_cpu = smp_core99_setup_cpu, + .give_timebase = smp_core99_give_timebase, + .take_timebase = smp_core99_take_timebase, +}; diff --git a/arch/ppc/platforms/pmac_time.c b/arch/ppc/platforms/pmac_time.c new file mode 100644 index 00000000000..09636546f44 --- /dev/null +++ b/arch/ppc/platforms/pmac_time.c @@ -0,0 +1,292 @@ +/* + * Support for periodic interrupts (100 per second) and for getting + * the current time from the RTC on Power Macintoshes. + * + * We use the decrementer register for our periodic interrupts. + * + * Paul Mackerras August 1996. + * Copyright (C) 1996 Paul Mackerras. + */ +#include <linux/config.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/param.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/init.h> +#include <linux/time.h> +#include <linux/adb.h> +#include <linux/cuda.h> +#include <linux/pmu.h> +#include <linux/hardirq.h> + +#include <asm/sections.h> +#include <asm/prom.h> +#include <asm/system.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/machdep.h> +#include <asm/time.h> +#include <asm/nvram.h> + +/* Apparently the RTC stores seconds since 1 Jan 1904 */ +#define RTC_OFFSET 2082844800 + +/* + * Calibrate the decrementer frequency with the VIA timer 1. + */ +#define VIA_TIMER_FREQ_6 4700000 /* time 1 frequency * 6 */ + +/* VIA registers */ +#define RS 0x200 /* skip between registers */ +#define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */ +#define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */ +#define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */ +#define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */ +#define ACR (11*RS) /* Auxiliary control register */ +#define IFR (13*RS) /* Interrupt flag register */ + +/* Bits in ACR */ +#define T1MODE 0xc0 /* Timer 1 mode */ +#define T1MODE_CONT 0x40 /* continuous interrupts */ + +/* Bits in IFR and IER */ +#define T1_INT 0x40 /* Timer 1 interrupt */ + +extern struct timezone sys_tz; + +long __init +pmac_time_init(void) +{ +#ifdef CONFIG_NVRAM + s32 delta = 0; + int dst; + + delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16; + delta |= ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xa)) << 8; + delta |= pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xb); + if (delta & 0x00800000UL) + delta |= 0xFF000000UL; + dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0); + printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60, + dst ? "on" : "off"); + return delta; +#else + return 0; +#endif +} + +unsigned long __pmac +pmac_get_rtc_time(void) +{ +#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) + struct adb_request req; + unsigned long now; +#endif + + /* Get the time from the RTC */ + switch (sys_ctrler) { +#ifdef CONFIG_ADB_CUDA + case SYS_CTRLER_CUDA: + if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0) + return 0; + while (!req.complete) + cuda_poll(); + if (req.reply_len != 7) + printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n", + req.reply_len); + now = (req.reply[3] << 24) + (req.reply[4] << 16) + + (req.reply[5] << 8) + req.reply[6]; + return now - RTC_OFFSET; +#endif /* CONFIG_ADB_CUDA */ +#ifdef CONFIG_ADB_PMU + case SYS_CTRLER_PMU: + if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0) + return 0; + while (!req.complete) + pmu_poll(); + if (req.reply_len != 4) + printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n", + req.reply_len); + now = (req.reply[0] << 24) + (req.reply[1] << 16) + + (req.reply[2] << 8) + req.reply[3]; + return now - RTC_OFFSET; +#endif /* CONFIG_ADB_PMU */ + default: ; + } + return 0; +} + +int __pmac +pmac_set_rtc_time(unsigned long nowtime) +{ +#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) + struct adb_request req; +#endif + + nowtime += RTC_OFFSET; + + switch (sys_ctrler) { +#ifdef CONFIG_ADB_CUDA + case SYS_CTRLER_CUDA: + if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME, + nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0) + return 0; + while (!req.complete) + cuda_poll(); + if ((req.reply_len != 3) && (req.reply_len != 7)) + printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n", + req.reply_len); + return 1; +#endif /* CONFIG_ADB_CUDA */ +#ifdef CONFIG_ADB_PMU + case SYS_CTRLER_PMU: + if (pmu_request(&req, NULL, 5, PMU_SET_RTC, + nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0) + return 0; + while (!req.complete) + pmu_poll(); + if (req.reply_len != 0) + printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n", + req.reply_len); + return 1; +#endif /* CONFIG_ADB_PMU */ + default: + return 0; + } +} + +/* + * Calibrate the decrementer register using VIA timer 1. + * This is used both on powermacs and CHRP machines. + */ +int __init +via_calibrate_decr(void) +{ + struct device_node *vias; + volatile unsigned char *via; + int count = VIA_TIMER_FREQ_6 / 100; + unsigned int dstart, dend; + + vias = find_devices("via-cuda"); + if (vias == 0) + vias = find_devices("via-pmu"); + if (vias == 0) + vias = find_devices("via"); + if (vias == 0 || vias->n_addrs == 0) + return 0; + via = (volatile unsigned char *) + ioremap(vias->addrs[0].address, vias->addrs[0].size); + + /* set timer 1 for continuous interrupts */ + out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT); + /* set the counter to a small value */ + out_8(&via[T1CH], 2); + /* set the latch to `count' */ + out_8(&via[T1LL], count); + out_8(&via[T1LH], count >> 8); + /* wait until it hits 0 */ + while ((in_8(&via[IFR]) & T1_INT) == 0) + ; + dstart = get_dec(); + /* clear the interrupt & wait until it hits 0 again */ + in_8(&via[T1CL]); + while ((in_8(&via[IFR]) & T1_INT) == 0) + ; + dend = get_dec(); + + tb_ticks_per_jiffy = (dstart - dend) / (6 * (HZ/100)); + tb_to_us = mulhwu_scale_factor(dstart - dend, 60000); + + printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n", + tb_ticks_per_jiffy, dstart - dend); + + iounmap((void*)via); + + return 1; +} + +#ifdef CONFIG_PMAC_PBOOK +/* + * Reset the time after a sleep. + */ +static int __pmac +time_sleep_notify(struct pmu_sleep_notifier *self, int when) +{ + static unsigned long time_diff; + unsigned long flags; + unsigned long seq; + + switch (when) { + case PBOOK_SLEEP_NOW: + do { + seq = read_seqbegin_irqsave(&xtime_lock, flags); + time_diff = xtime.tv_sec - pmac_get_rtc_time(); + } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); + break; + case PBOOK_WAKE: + write_seqlock_irqsave(&xtime_lock, flags); + xtime.tv_sec = pmac_get_rtc_time() + time_diff; + xtime.tv_nsec = 0; + last_rtc_update = xtime.tv_sec; + write_sequnlock_irqrestore(&xtime_lock, flags); + break; + } + return PBOOK_SLEEP_OK; +} + +static struct pmu_sleep_notifier time_sleep_notifier __pmacdata = { + time_sleep_notify, SLEEP_LEVEL_MISC, +}; +#endif /* CONFIG_PMAC_PBOOK */ + +/* + * Query the OF and get the decr frequency. + * This was taken from the pmac time_init() when merging the prep/pmac + * time functions. + */ +void __init +pmac_calibrate_decr(void) +{ + struct device_node *cpu; + unsigned int freq, *fp; + +#ifdef CONFIG_PMAC_PBOOK + pmu_register_sleep_notifier(&time_sleep_notifier); +#endif /* CONFIG_PMAC_PBOOK */ + + /* We assume MacRISC2 machines have correct device-tree + * calibration. That's better since the VIA itself seems + * to be slightly off. --BenH + */ + if (!machine_is_compatible("MacRISC2") && + !machine_is_compatible("MacRISC3") && + !machine_is_compatible("MacRISC4")) + if (via_calibrate_decr()) + return; + + /* Special case: QuickSilver G4s seem to have a badly calibrated + * timebase-frequency in OF, VIA is much better on these. We should + * probably implement calibration based on the KL timer on these + * machines anyway... -BenH + */ + if (machine_is_compatible("PowerMac3,5")) + if (via_calibrate_decr()) + return; + /* + * The cpu node should have a timebase-frequency property + * to tell us the rate at which the decrementer counts. + */ + cpu = find_type_devices("cpu"); + if (cpu == 0) + panic("can't find cpu node in time_init"); + fp = (unsigned int *) get_property(cpu, "timebase-frequency", NULL); + if (fp == 0) + panic("can't get cpu timebase frequency"); + freq = *fp; + printk("time_init: decrementer frequency = %u.%.6u MHz\n", + freq/1000000, freq%1000000); + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); +} diff --git a/arch/ppc/platforms/powerpmc250.c b/arch/ppc/platforms/powerpmc250.c new file mode 100644 index 00000000000..0abe15159e6 --- /dev/null +++ b/arch/ppc/platforms/powerpmc250.c @@ -0,0 +1,383 @@ +/* + * arch/ppc/platforms/powerpmc250.c + * + * Board setup routines for Force PowerPMC-250 Processor PMC + * + * Author: Troy Benjegerdes <tbenjegerdes@mvista.com> + * Borrowed heavily from prpmc750_*.c by + * Matt Porter <mporter@mvista.com> + * + * 2001 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/types.h> +#include <linux/major.h> +#include <linux/initrd.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/slab.h> +#include <linux/seq_file.h> +#include <linux/ide.h> +#include <linux/root_dev.h> + +#include <asm/byteorder.h> +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/machdep.h> +#include <asm/time.h> +#include <platforms/powerpmc250.h> +#include <asm/open_pic.h> +#include <asm/pci-bridge.h> +#include <asm/mpc10x.h> +#include <asm/uaccess.h> +#include <asm/bootinfo.h> + +extern void powerpmc250_find_bridges(void); +extern unsigned long loops_per_jiffy; + +static u_char powerpmc250_openpic_initsenses[] __initdata = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, /* PMC INTA (also MPC107 output interrupt INTA) */ + 1, /* PMC INTB (also I82559 Ethernet controller) */ + 1, /* PMC INTC */ + 1, /* PMC INTD */ + 0, /* DUART interrupt (active high) */ +}; + +static int +powerpmc250_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m,"machine\t\t: Force PowerPMC250\n"); + + return 0; +} + +static void __init +powerpmc250_setup_arch(void) +{ + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000/HZ; + + /* Lookup PCI host bridges */ + powerpmc250_find_bridges(); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_SDA2; +#endif + + printk("Force PowerPMC250 port (C) 2001 MontaVista Software, Inc. (source@mvista.com)\n"); +} + +#if 0 +/* + * Compute the PrPMC750's bus speed using the baud clock as a + * reference. + */ +unsigned long __init powerpmc250_get_bus_speed(void) +{ + unsigned long tbl_start, tbl_end; + unsigned long current_state, old_state, bus_speed; + unsigned char lcr, dll, dlm; + int baud_divisor, count; + + /* Read the UART's baud clock divisor */ + lcr = readb(PRPMC750_SERIAL_0_LCR); + writeb(lcr | UART_LCR_DLAB, PRPMC750_SERIAL_0_LCR); + dll = readb(PRPMC750_SERIAL_0_DLL); + dlm = readb(PRPMC750_SERIAL_0_DLM); + writeb(lcr & ~UART_LCR_DLAB, PRPMC750_SERIAL_0_LCR); + baud_divisor = (dlm << 8) | dll; + + /* + * Use the baud clock divisor and base baud clock + * to determine the baud rate and use that as + * the number of baud clock edges we use for + * the time base sample. Make it half the baud + * rate. + */ + count = PRPMC750_BASE_BAUD / (baud_divisor * 16); + + /* Find the first edge of the baud clock */ + old_state = readb(PRPMC750_STATUS_REG) & PRPMC750_BAUDOUT_MASK; + do { + current_state = readb(PRPMC750_STATUS_REG) & + PRPMC750_BAUDOUT_MASK; + } while(old_state == current_state); + + old_state = current_state; + + /* Get the starting time base value */ + tbl_start = get_tbl(); + + /* + * Loop until we have found a number of edges equal + * to half the count (half the baud rate) + */ + do { + do { + current_state = readb(PRPMC750_STATUS_REG) & + PRPMC750_BAUDOUT_MASK; + } while(old_state == current_state); + old_state = current_state; + } while (--count); + + /* Get the ending time base value */ + tbl_end = get_tbl(); + + /* Compute bus speed */ + bus_speed = (tbl_end-tbl_start)*128; + + return bus_speed; +} +#endif + +static void __init +powerpmc250_calibrate_decr(void) +{ + unsigned long freq; + int divisor = 4; + + //freq = powerpmc250_get_bus_speed(); +#warning hardcoded bus freq + freq = 100000000; + + tb_ticks_per_jiffy = freq / (HZ * divisor); + tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000); +} + +static void +powerpmc250_restart(char *cmd) +{ + local_irq_disable(); + /* Hard reset */ + writeb(0x11, 0xfe000332); + while(1); +} + +static void +powerpmc250_halt(void) +{ + local_irq_disable(); + while (1); +} + +static void +powerpmc250_power_off(void) +{ + powerpmc250_halt(); +} + +static void __init +powerpmc250_init_IRQ(void) +{ + + OpenPIC_InitSenses = powerpmc250_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof(powerpmc250_openpic_initsenses); + mpc10x_set_openpic(); +} + +/* + * Set BAT 3 to map 0xf0000000 to end of physical memory space. + */ +static __inline__ void +powerpmc250_set_bat(void) +{ + unsigned long bat3u, bat3l; + static int mapping_set = 0; + + if (!mapping_set) + { + __asm__ __volatile__( + " lis %0,0xf000\n \ + ori %1,%0,0x002a\n \ + ori %0,%0,0x1ffe\n \ + mtspr 0x21e,%0\n \ + mtspr 0x21f,%1\n \ + isync\n \ + sync " + : "=r" (bat3u), "=r" (bat3l)); + + mapping_set = 1; + } + return; +} + +static unsigned long __init +powerpmc250_find_end_of_memory(void) +{ + /* Cover I/O space with a BAT */ + /* yuck, better hope your ram size is a power of 2 -- paulus */ + powerpmc250_set_bat(); + + return mpc10x_get_mem_size(MPC10X_MEM_MAP_B); +} + +static void __init +powerpmc250_map_io(void) +{ + io_block_mapping(0xfe000000, 0xfe000000, 0x02000000, _PAGE_IO); +} + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + parse_bootinfo(find_bootinfo()); + +#ifdef CONFIG_BLK_DEV_INITRD + if ( r4 ) + { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif + + /* Copy cmd_line parameters */ + if ( r6) + { + *(char *)(r7 + KERNELBASE) = 0; + strcpy(cmd_line, (char *)(r6 + KERNELBASE)); + } + + isa_io_base = MPC10X_MAPB_ISA_IO_BASE; + isa_mem_base = MPC10X_MAPB_ISA_MEM_BASE; + pci_dram_offset = MPC10X_MAPB_DRAM_OFFSET; + + ppc_md.setup_arch = powerpmc250_setup_arch; + ppc_md.show_cpuinfo = powerpmc250_show_cpuinfo; + ppc_md.init_IRQ = powerpmc250_init_IRQ; + ppc_md.get_irq = openpic_get_irq; + + ppc_md.find_end_of_memory = powerpmc250_find_end_of_memory; + ppc_md.setup_io_mappings = powerpmc250_map_io; + + ppc_md.restart = powerpmc250_restart; + ppc_md.power_off = powerpmc250_power_off; + ppc_md.halt = powerpmc250_halt; + + /* PowerPMC250 has no timekeeper part */ + ppc_md.time_init = NULL; + ppc_md.get_rtc_time = NULL; + ppc_md.set_rtc_time = NULL; + ppc_md.calibrate_decr = powerpmc250_calibrate_decr; +} + + +/* + * (This used to be arch/ppc/platforms/powerpmc250_pci.c) + * + * PCI support for Force PowerPMC250 + * + */ + +#undef DEBUG +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif /* DEBUG */ + +static inline int __init +powerpmc250_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {17, 0, 0, 0}, /* Device 11 - 82559 */ + {0, 0, 0, 0}, /* 12 */ + {0, 0, 0, 0}, /* 13 */ + {0, 0, 0, 0}, /* 14 */ + {0, 0, 0, 0}, /* 15 */ + {16, 17, 18, 19}, /* Device 16 - PMC A1?? */ + }; + const long min_idsel = 11, max_idsel = 16, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +}; + +static int +powerpmc250_exclude_device(u_char bus, u_char devfn) +{ + /* + * While doing PCI Scan the MPC107 will 'detect' itself as + * device on the PCI Bus, will create an incorrect response and + * later will respond incorrectly to Configuration read coming + * from another device. + * + * The work around is that when doing a PCI Scan one + * should skip its own device number in the scan. + * + * The top IDsel is AD13 and the middle is AD14. + * + * -- Note from force + */ + + if ((bus == 0) && (PCI_SLOT(devfn) == 13 || PCI_SLOT(devfn) == 14)) { + return PCIBIOS_DEVICE_NOT_FOUND; + } + else { + return PCIBIOS_SUCCESSFUL; + } +} + +void __init +powerpmc250_find_bridges(void) +{ + struct pci_controller* hose; + + hose = pcibios_alloc_controller(); + if (!hose){ + printk("Can't allocate PCI 'hose' structure!!!\n"); + return; + } + + hose->first_busno = 0; + hose->last_busno = 0xff; + + if (mpc10x_bridge_init(hose, + MPC10X_MEM_MAP_B, + MPC10X_MEM_MAP_B, + MPC10X_MAPB_EUMB_BASE) == 0) { + + hose->mem_resources[0].end = 0xffffffff; + + hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); + + /* ppc_md.pcibios_fixup = pcore_pcibios_fixup; */ + ppc_md.pci_swizzle = common_swizzle; + + ppc_md.pci_exclude_device = powerpmc250_exclude_device; + ppc_md.pci_map_irq = powerpmc250_map_irq; + } else { + if (ppc_md.progress) + ppc_md.progress("Bridge init failed", 0x100); + printk("Host bridge init failed\n"); + } + +} diff --git a/arch/ppc/platforms/powerpmc250.h b/arch/ppc/platforms/powerpmc250.h new file mode 100644 index 00000000000..41a6dc88191 --- /dev/null +++ b/arch/ppc/platforms/powerpmc250.h @@ -0,0 +1,52 @@ +/* + * include/asm-ppc/platforms/powerpmc250.h + * + * Definitions for Force PowerPMC-250 board support + * + * Author: Troy Benjegerdes <tbenjegerdes@mvista.com> + * + * Borrowed heavily from prpmc750.h by Matt Porter <mporter@mvista.com> + * + * 2001-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. + */ + +#ifndef __ASMPPC_POWERPMC250_H +#define __ASMPPC_POWERPMC250_H + +#define POWERPMC250_PCI_CONFIG_ADDR 0x80000cf8 +#define POWERPMC250_PCI_CONFIG_DATA 0x80000cfc + +#define POWERPMC250_PCI_PHY_MEM_BASE 0xc0000000 +#define POWERPMC250_PCI_MEM_BASE 0xf0000000 +#define POWERPMC250_PCI_IO_BASE 0x80000000 + +#define POWERPMC250_ISA_IO_BASE POWERPMC250_PCI_IO_BASE +#define POWERPMC250_ISA_MEM_BASE POWERPMC250_PCI_MEM_BASE +#define POWERPMC250_PCI_MEM_OFFSET POWERPMC250_PCI_PHY_MEM_BASE + +#define POWERPMC250_SYS_MEM_BASE 0x80000000 + +#define POWERPMC250_HAWK_SMC_BASE 0xfef80000 + +#define POWERPMC250_BASE_BAUD 12288000 +#define POWERPMC250_SERIAL 0xff000000 +#define POWERPMC250_SERIAL_IRQ 20 + +/* UART Defines. */ +#define RS_TABLE_SIZE 1 + +#define BASE_BAUD (POWERPMC250_BASE_BAUD / 16) + +#define STD_COM_FLAGS ASYNC_BOOT_AUTOCONF + +#define SERIAL_PORT_DFNS \ + { 0, BASE_BAUD, POWERPMC250_SERIAL, POWERPMC250_SERIAL_IRQ, \ + STD_COM_FLAGS, /* ttyS0 */ \ + iomem_base: (u8 *)POWERPMC250_SERIAL, \ + iomem_reg_shift: 0, \ + io_type: SERIAL_IO_MEM } + +#endif /* __ASMPPC_POWERPMC250_H */ diff --git a/arch/ppc/platforms/pplus.c b/arch/ppc/platforms/pplus.c new file mode 100644 index 00000000000..65705c91179 --- /dev/null +++ b/arch/ppc/platforms/pplus.c @@ -0,0 +1,917 @@ +/* + * arch/ppc/platforms/pplus.c + * + * Board and PCI setup routines for MCG PowerPlus + * + * Author: Randy Vinson <rvinson@mvista.com> + * + * Derived from original PowerPlus PReP work by + * Cort Dougan, Johnnie Peters, Matt Porter, and + * Troy Benjegerdes. + * + * 2001-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. + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/console.h> +#include <linux/pci.h> +#include <linux/irq.h> +#include <linux/ide.h> +#include <linux/seq_file.h> +#include <linux/root_dev.h> + +#include <asm/system.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/dma.h> +#include <asm/machdep.h> +#include <asm/prep_nvram.h> +#include <asm/vga.h> +#include <asm/i8259.h> +#include <asm/open_pic.h> +#include <asm/hawk.h> +#include <asm/todc.h> +#include <asm/bootinfo.h> +#include <asm/kgdb.h> +#include <asm/reg.h> + +#include "pplus.h" + +#undef DUMP_DBATS + +TODC_ALLOC(); + +extern void pplus_setup_hose(void); +extern void pplus_set_VIA_IDE_native(void); + +extern unsigned long loops_per_jiffy; +unsigned char *Motherboard_map_name; + +/* Tables for known hardware */ + +/* Motorola Mesquite */ +static inline int +mesquite_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * MPIC interrupts for various IDSEL values (MPIC IRQ0 = + * Linux IRQ16 (to leave room for ISA IRQs at 0-15). + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {18, 0, 0, 0}, /* IDSEL 14 - Enet 0 */ + { 0, 0, 0, 0}, /* IDSEL 15 - unused */ + {19, 19, 19, 19}, /* IDSEL 16 - PMC Slot 1 */ + { 0, 0, 0, 0}, /* IDSEL 17 - unused */ + { 0, 0, 0, 0}, /* IDSEL 18 - unused */ + { 0, 0, 0, 0}, /* IDSEL 19 - unused */ + {24, 25, 26, 27}, /* IDSEL 20 - P2P bridge (to cPCI 1) */ + { 0, 0, 0, 0}, /* IDSEL 21 - unused */ + {28, 29, 30, 31} /* IDSEL 22 - P2P bridge (to cPCI 2) */ + }; + + const long min_idsel = 14, max_idsel = 22, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +} + +/* Motorola Sitka */ +static inline int +sitka_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * MPIC interrupts for various IDSEL values (MPIC IRQ0 = + * Linux IRQ16 (to leave room for ISA IRQs at 0-15). + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {18, 0, 0, 0}, /* IDSEL 14 - Enet 0 */ + { 0, 0, 0, 0}, /* IDSEL 15 - unused */ + {25, 26, 27, 28}, /* IDSEL 16 - PMC Slot 1 */ + {28, 25, 26, 27}, /* IDSEL 17 - PMC Slot 2 */ + { 0, 0, 0, 0}, /* IDSEL 18 - unused */ + { 0, 0, 0, 0}, /* IDSEL 19 - unused */ + {20, 0, 0, 0} /* IDSEL 20 - P2P bridge (to cPCI) */ + }; + + const long min_idsel = 14, max_idsel = 20, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +} + +/* Motorola MTX */ +static inline int +MTX_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * MPIC interrupts for various IDSEL values (MPIC IRQ0 = + * Linux IRQ16 (to leave room for ISA IRQs at 0-15). + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {19, 0, 0, 0}, /* IDSEL 12 - SCSI */ + { 0, 0, 0, 0}, /* IDSEL 13 - unused */ + {18, 0, 0, 0}, /* IDSEL 14 - Enet */ + { 0, 0, 0, 0}, /* IDSEL 15 - unused */ + {25, 26, 27, 28}, /* IDSEL 16 - PMC Slot 1 */ + {26, 27, 28, 25}, /* IDSEL 17 - PMC Slot 2 */ + {27, 28, 25, 26} /* IDSEL 18 - PCI Slot 3 */ + }; + + const long min_idsel = 12, max_idsel = 18, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +} + +/* Motorola MTX Plus */ +/* Secondary bus interrupt routing is not supported yet */ +static inline int +MTXplus_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * MPIC interrupts for various IDSEL values (MPIC IRQ0 = + * Linux IRQ16 (to leave room for ISA IRQs at 0-15). + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {19, 0, 0, 0}, /* IDSEL 12 - SCSI */ + { 0, 0, 0, 0}, /* IDSEL 13 - unused */ + {18, 0, 0, 0}, /* IDSEL 14 - Enet 1 */ + { 0, 0, 0, 0}, /* IDSEL 15 - unused */ + {25, 26, 27, 28}, /* IDSEL 16 - PCI Slot 1P */ + {26, 27, 28, 25}, /* IDSEL 17 - PCI Slot 2P */ + {27, 28, 25, 26}, /* IDSEL 18 - PCI Slot 3P */ + {26, 0, 0, 0}, /* IDSEL 19 - Enet 2 */ + { 0, 0, 0, 0} /* IDSEL 20 - P2P Bridge */ + }; + + const long min_idsel = 12, max_idsel = 20, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +} + +static inline int +Genesis2_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + /* 2600 + * Raven 31 + * ISA 11 + * SCSI 12 - IRQ3 + * Univ 13 + * eth 14 - IRQ2 + * VGA 15 - IRQ4 + * PMC1 16 - IRQ9,10,11,12 = PMC1 A-D + * PMC2 17 - IRQ12,9,10,11 = A-D + * SCSI2 18 - IRQ11 + * eth2 19 - IRQ10 + * PCIX 20 - IRQ9,10,11,12 = PCI A-D + */ + + /* 2400 + * Hawk 31 + * ISA 11 + * Univ 13 + * eth 14 - IRQ2 + * PMC1 16 - IRQ9,10,11,12 = PMC A-D + * PMC2 17 - IRQ12,9,10,11 = PMC A-D + * PCIX 20 - IRQ9,10,11,12 = PMC A-D + */ + + /* 2300 + * Raven 31 + * ISA 11 + * Univ 13 + * eth 14 - IRQ2 + * PMC1 16 - 9,10,11,12 = A-D + * PMC2 17 - 9,10,11,12 = B,C,D,A + */ + + static char pci_irq_table[][4] = + /* + * MPIC interrupts for various IDSEL values (MPIC IRQ0 = + * Linux IRQ16 (to leave room for ISA IRQs at 0-15). + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {19, 0, 0, 0}, /* IDSEL 12 - SCSI */ + { 0, 0, 0, 0}, /* IDSEL 13 - Universe PCI - VME */ + {18, 0, 0, 0}, /* IDSEL 14 - Enet 1 */ + { 0, 0, 0, 0}, /* IDSEL 15 - unused */ + {25, 26, 27, 28}, /* IDSEL 16 - PCI/PMC Slot 1P */ + {28, 25, 26, 27}, /* IDSEL 17 - PCI/PMC Slot 2P */ + {27, 28, 25, 26}, /* IDSEL 18 - PCI Slot 3P */ + {26, 0, 0, 0}, /* IDSEL 19 - Enet 2 */ + {25, 26, 27, 28} /* IDSEL 20 - P2P Bridge */ + }; + + const long min_idsel = 12, max_idsel = 20, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +} + +#define MOTOROLA_CPUTYPE_REG 0x800 +#define MOTOROLA_BASETYPE_REG 0x803 +#define MPIC_RAVEN_ID 0x48010000 +#define MPIC_HAWK_ID 0x48030000 +#define MOT_PROC2_BIT 0x800 + +static u_char pplus_openpic_initsenses[] __initdata = { + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* MVME2600_INT_SIO */ + (IRQ_SENSE_EDGE | IRQ_POLARITY_NEGATIVE),/*MVME2600_INT_FALCN_ECC_ERR */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/*MVME2600_INT_PCI_ETHERNET */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_SCSI */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/*MVME2600_INT_PCI_GRAPHICS */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME3 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTA */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTB */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTC */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTD */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_LM_SIG0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_LM_SIG1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), +}; + +int mot_entry = -1; +int prep_keybd_present = 1; +int mot_multi = 0; + +struct brd_info { + /* 0x100 mask assumes for Raven and Hawk boards that the level/edge + * are set */ + int cpu_type; + /* 0x200 if this board has a Hawk chip. */ + int base_type; + /* or'ed with 0x80 if this board should be checked for multi CPU */ + int max_cpu; + const char *name; + int (*map_irq) (struct pci_dev *, unsigned char, unsigned char); +}; +struct brd_info mot_info[] = { + {0x300, 0x00, 0x00, "MVME 2400", Genesis2_map_irq}, + {0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)", mesquite_map_irq}, + {0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)", sitka_map_irq}, + {0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC", mesquite_map_irq}, + {0x1E0, 0xF6, 0x80, "MTX Plus", MTXplus_map_irq}, + {0x1E0, 0xF6, 0x81, "Dual MTX Plus", MTXplus_map_irq}, + {0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port", MTX_map_irq}, + {0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port", MTX_map_irq}, + {0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port", MTX_map_irq}, + {0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port", MTX_map_irq}, + {0x1E0, 0xF9, 0x00, "MVME 2300", Genesis2_map_irq}, + {0x1E0, 0xFA, 0x00, "MVME 2300SC/2600", Genesis2_map_irq}, + {0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M", Genesis2_map_irq}, + {0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761", Genesis2_map_irq}, + {0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M", Genesis2_map_irq}, + {0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M", Genesis2_map_irq}, + {0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761", Genesis2_map_irq}, + {0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761", Genesis2_map_irq}, + {0x000, 0x00, 0x00, "", NULL} +}; + +void __init pplus_set_board_type(void) +{ + unsigned char cpu_type; + unsigned char base_mod; + int entry; + unsigned short devid; + unsigned long *ProcInfo = NULL; + + cpu_type = inb(MOTOROLA_CPUTYPE_REG) & 0xF0; + base_mod = inb(MOTOROLA_BASETYPE_REG); + early_read_config_word(0, 0, 0, PCI_VENDOR_ID, &devid); + + for (entry = 0; mot_info[entry].cpu_type != 0; entry++) { + /* Check for Hawk chip */ + if (mot_info[entry].cpu_type & 0x200) { + if (devid != PCI_DEVICE_ID_MOTOROLA_HAWK) + continue; + } else { + /* store the system config register for later use. */ + ProcInfo = + (unsigned long *)ioremap(PPLUS_SYS_CONFIG_REG, 4); + + /* Check non hawk boards */ + if ((mot_info[entry].cpu_type & 0xff) != cpu_type) + continue; + + if (mot_info[entry].base_type == 0) { + mot_entry = entry; + break; + } + + if (mot_info[entry].base_type != base_mod) + continue; + } + + if (!(mot_info[entry].max_cpu & 0x80)) { + mot_entry = entry; + break; + } + + /* processor 1 not present and max processor zero indicated */ + if ((*ProcInfo & MOT_PROC2_BIT) + && !(mot_info[entry].max_cpu & 0x7f)) { + mot_entry = entry; + break; + } + + /* processor 1 present and max processor zero indicated */ + if (!(*ProcInfo & MOT_PROC2_BIT) + && (mot_info[entry].max_cpu & 0x7f)) { + mot_entry = entry; + break; + } + + /* Indicate to system if this is a multiprocessor board */ + if (!(*ProcInfo & MOT_PROC2_BIT)) + mot_multi = 1; + } + + if (mot_entry == -1) + /* No particular cpu type found - assume Mesquite (MCP750) */ + mot_entry = 1; + + Motherboard_map_name = (unsigned char *)mot_info[mot_entry].name; + ppc_md.pci_map_irq = mot_info[mot_entry].map_irq; +} +void __init pplus_pib_init(void) +{ + unsigned char reg; + unsigned short short_reg; + + struct pci_dev *dev = NULL; + + /* + * Perform specific configuration for the Via Tech or + * or Winbond PCI-ISA-Bridge part. + */ + if ((dev = pci_get_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_82C586_1, dev))) { + /* + * PPCBUG does not set the enable bits + * for the IDE device. Force them on here. + */ + pci_read_config_byte(dev, 0x40, ®); + + reg |= 0x03; /* IDE: Chip Enable Bits */ + pci_write_config_byte(dev, 0x40, reg); + } + + if ((dev = pci_get_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_82C586_2, + dev)) && (dev->devfn = 0x5a)) { + /* Force correct USB interrupt */ + dev->irq = 11; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + } + + if ((dev = pci_get_device(PCI_VENDOR_ID_WINBOND, + PCI_DEVICE_ID_WINBOND_83C553, dev))) { + /* Clear PCI Interrupt Routing Control Register. */ + short_reg = 0x0000; + pci_write_config_word(dev, 0x44, short_reg); + /* Route IDE interrupts to IRQ 14 */ + reg = 0xEE; + pci_write_config_byte(dev, 0x43, reg); + } + + if ((dev = pci_get_device(PCI_VENDOR_ID_WINBOND, + PCI_DEVICE_ID_WINBOND_82C105, dev))) { + /* + * Disable LEGIRQ mode so PCI INTS are routed + * directly to the 8259 and enable both channels + */ + pci_write_config_dword(dev, 0x40, 0x10ff0033); + + /* Force correct IDE interrupt */ + dev->irq = 14; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + } + pci_dev_put(dev); +} + +void __init pplus_set_VIA_IDE_legacy(void) +{ + unsigned short vend, dev; + + early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_VENDOR_ID, &vend); + early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_DEVICE_ID, &dev); + + if ((vend == PCI_VENDOR_ID_VIA) && + (dev == PCI_DEVICE_ID_VIA_82C586_1)) { + unsigned char temp; + + /* put back original "standard" port base addresses */ + early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1), + PCI_BASE_ADDRESS_0, 0x1f1); + early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1), + PCI_BASE_ADDRESS_1, 0x3f5); + early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1), + PCI_BASE_ADDRESS_2, 0x171); + early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1), + PCI_BASE_ADDRESS_3, 0x375); + early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1), + PCI_BASE_ADDRESS_4, 0xcc01); + + /* put into legacy mode */ + early_read_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG, + &temp); + temp &= ~0x05; + early_write_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG, + temp); + } +} + +void pplus_set_VIA_IDE_native(void) +{ + unsigned short vend, dev; + + early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_VENDOR_ID, &vend); + early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_DEVICE_ID, &dev); + + if ((vend == PCI_VENDOR_ID_VIA) && + (dev == PCI_DEVICE_ID_VIA_82C586_1)) { + unsigned char temp; + + /* put into native mode */ + early_read_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG, + &temp); + temp |= 0x05; + early_write_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG, + temp); + } +} + +void __init pplus_pcibios_fixup(void) +{ + + unsigned char reg; + unsigned short devid; + unsigned char base_mod; + + printk(KERN_INFO "Setting PCI interrupts for a \"%s\"\n", + Motherboard_map_name); + + /* Setup the Winbond or Via PIB */ + pplus_pib_init(); + + /* Set up floppy in PS/2 mode */ + outb(0x09, SIO_CONFIG_RA); + reg = inb(SIO_CONFIG_RD); + reg = (reg & 0x3F) | 0x40; + outb(reg, SIO_CONFIG_RD); + outb(reg, SIO_CONFIG_RD); /* Have to write twice to change! */ + + /* This is a hack. If this is a 2300 or 2400 mot board then there is + * no keyboard controller and we have to indicate that. + */ + + early_read_config_word(0, 0, 0, PCI_VENDOR_ID, &devid); + base_mod = inb(MOTOROLA_BASETYPE_REG); + if ((devid == PCI_DEVICE_ID_MOTOROLA_HAWK) || + (base_mod == 0xF9) || (base_mod == 0xFA) || (base_mod == 0xE1)) + prep_keybd_present = 0; +} + +void __init pplus_find_bridges(void) +{ + struct pci_controller *hose; + + hose = pcibios_alloc_controller(); + if (!hose) + return; + + hose->first_busno = 0; + hose->last_busno = 0xff; + + hose->pci_mem_offset = PREP_ISA_MEM_BASE; + hose->io_base_virt = (void *)PREP_ISA_IO_BASE; + + pci_init_resource(&hose->io_resource, PPLUS_PCI_IO_START, + PPLUS_PCI_IO_END, IORESOURCE_IO, "PCI host bridge"); + pci_init_resource(&hose->mem_resources[0], PPLUS_PROC_PCI_MEM_START, + PPLUS_PROC_PCI_MEM_END, IORESOURCE_MEM, + "PCI host bridge"); + + hose->io_space.start = PPLUS_PCI_IO_START; + hose->io_space.end = PPLUS_PCI_IO_END; + hose->mem_space.start = PPLUS_PCI_MEM_START; + hose->mem_space.end = PPLUS_PCI_MEM_END - HAWK_MPIC_SIZE; + + if (hawk_init(hose, PPLUS_HAWK_PPC_REG_BASE, PPLUS_PROC_PCI_MEM_START, + PPLUS_PROC_PCI_MEM_END - HAWK_MPIC_SIZE, + PPLUS_PROC_PCI_IO_START, PPLUS_PROC_PCI_IO_END, + PPLUS_PROC_PCI_MEM_END - HAWK_MPIC_SIZE + 1) + != 0) { + printk(KERN_CRIT "Could not initialize host bridge\n"); + + } + + pplus_set_VIA_IDE_legacy(); + + hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); + + ppc_md.pcibios_fixup = pplus_pcibios_fixup; + ppc_md.pci_swizzle = common_swizzle; +} + +static int pplus_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "vendor\t\t: Motorola MCG\n"); + seq_printf(m, "machine\t\t: %s\n", Motherboard_map_name); + + return 0; +} + +static void __init pplus_setup_arch(void) +{ + struct pci_controller *hose; + + if (ppc_md.progress) + ppc_md.progress("pplus_setup_arch: enter", 0); + + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000; + + if (ppc_md.progress) + ppc_md.progress("pplus_setup_arch: find_bridges", 0); + + /* Setup PCI host bridge */ + pplus_find_bridges(); + + hose = pci_bus_to_hose(0); + isa_io_base = (ulong) hose->io_base_virt; + + if (ppc_md.progress) + ppc_md.progress("pplus_setup_arch: set_board_type", 0); + + pplus_set_board_type(); + + /* Enable L2. Assume we don't need to flush -- Cort */ + *(unsigned char *)(PPLUS_L2_CONTROL_REG) |= 3; + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_SDA2; +#endif + + printk(KERN_INFO "Motorola PowerPlus Platform\n"); + printk(KERN_INFO + "Port by MontaVista Software, Inc. (source@mvista.com)\n"); + +#ifdef CONFIG_VGA_CONSOLE + /* remap the VGA memory */ + vgacon_remap_base = (unsigned long)ioremap(PPLUS_ISA_MEM_BASE, + 0x08000000); + conswitchp = &vga_con; +#endif +#ifdef CONFIG_PPCBUG_NVRAM + /* Read in NVRAM data */ + init_prep_nvram(); + + /* if no bootargs, look in NVRAM */ + if (cmd_line[0] == '\0') { + char *bootargs; + bootargs = prep_nvram_get_var("bootargs"); + if (bootargs != NULL) { + strcpy(cmd_line, bootargs); + /* again.. */ + strcpy(saved_command_line, cmd_line); + } + } +#endif + if (ppc_md.progress) + ppc_md.progress("pplus_setup_arch: exit", 0); +} + +static void pplus_restart(char *cmd) +{ + unsigned long i = 10000; + + local_irq_disable(); + + /* set VIA IDE controller into native mode */ + pplus_set_VIA_IDE_native(); + + /* set exception prefix high - to the prom */ + _nmask_and_or_msr(0, MSR_IP); + + /* make sure bit 0 (reset) is a 0 */ + outb(inb(0x92) & ~1L, 0x92); + /* signal a reset to system control port A - soft reset */ + outb(inb(0x92) | 1, 0x92); + + while (i != 0) + i++; + panic("restart failed\n"); +} + +static void pplus_halt(void) +{ + /* set exception prefix high - to the prom */ + _nmask_and_or_msr(MSR_EE, MSR_IP); + + /* make sure bit 0 (reset) is a 0 */ + outb(inb(0x92) & ~1L, 0x92); + /* signal a reset to system control port A - soft reset */ + outb(inb(0x92) | 1, 0x92); + + while (1) ; + /* + * Not reached + */ +} + +static void pplus_power_off(void) +{ + pplus_halt(); +} + +static unsigned int pplus_irq_canonicalize(u_int irq) +{ + if (irq == 2) + return 9; + else + return irq; +} + +static void __init pplus_init_IRQ(void) +{ + int i; + + if (ppc_md.progress) + ppc_md.progress("init_irq: enter", 0); + + OpenPIC_InitSenses = pplus_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof(pplus_openpic_initsenses); + + if (OpenPIC_Addr != NULL) { + + openpic_set_sources(0, 16, OpenPIC_Addr + 0x10000); + openpic_init(NUM_8259_INTERRUPTS); + openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade", + i8259_irq); + ppc_md.get_irq = openpic_get_irq; + } + + for (i = 0; i < NUM_8259_INTERRUPTS; i++) + irq_desc[i].handler = &i8259_pic; + + i8259_init(0); + + if (ppc_md.progress) + ppc_md.progress("init_irq: exit", 0); +} + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +/* + * IDE stuff. + */ +static int pplus_ide_default_irq(unsigned long base) +{ + switch (base) { + case 0x1f0: + return 14; + case 0x170: + return 15; + default: + return 0; + } +} + +static unsigned long pplus_ide_default_io_base(int index) +{ + switch (index) { + case 0: + return 0x1f0; + case 1: + return 0x170; + default: + return 0; + } +} + +static void __init +pplus_ide_init_hwif_ports(hw_regs_t * hw, unsigned long data_port, + unsigned long ctrl_port, int *irq) +{ + unsigned long reg = data_port; + int i; + + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + hw->io_ports[i] = reg; + reg += 1; + } + + if (ctrl_port) + hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; + else + hw->io_ports[IDE_CONTROL_OFFSET] = + hw->io_ports[IDE_DATA_OFFSET] + 0x206; + + if (irq != NULL) + *irq = pplus_ide_default_irq(data_port); +} +#endif + +#ifdef CONFIG_SMP +/* PowerPlus (MTX) support */ +static int __init smp_pplus_probe(void) +{ + extern int mot_multi; + + if (mot_multi) { + openpic_request_IPIs(); + smp_hw_index[1] = 1; + return 2; + } + + return 1; +} + +static void __init smp_pplus_kick_cpu(int nr) +{ + *(unsigned long *)KERNELBASE = nr; + asm volatile ("dcbf 0,%0"::"r" (KERNELBASE):"memory"); + printk(KERN_INFO "CPU1 reset, waiting\n"); +} + +static void __init smp_pplus_setup_cpu(int cpu_nr) +{ + if (OpenPIC_Addr) + do_openpic_setup_cpu(); +} + +static struct smp_ops_t pplus_smp_ops = { + smp_openpic_message_pass, + smp_pplus_probe, + smp_pplus_kick_cpu, + smp_pplus_setup_cpu, + .give_timebase = smp_generic_give_timebase, + .take_timebase = smp_generic_take_timebase, +}; +#endif /* CONFIG_SMP */ + +#ifdef DUMP_DBATS +static void print_dbat(int idx, u32 bat) +{ + + char str[64]; + + sprintf(str, "DBAT%c%c = 0x%08x\n", + (char)((idx - DBAT0U) / 2) + '0', (idx & 1) ? 'L' : 'U', bat); + ppc_md.progress(str, 0); +} + +#define DUMP_DBAT(x) \ + do { \ + u32 __temp = mfspr(x);\ + print_dbat(x, __temp); \ + } while (0) + +static void dump_dbats(void) +{ + if (ppc_md.progress) { + DUMP_DBAT(DBAT0U); + DUMP_DBAT(DBAT0L); + DUMP_DBAT(DBAT1U); + DUMP_DBAT(DBAT1L); + DUMP_DBAT(DBAT2U); + DUMP_DBAT(DBAT2L); + DUMP_DBAT(DBAT3U); + DUMP_DBAT(DBAT3L); + } +} +#endif + +static unsigned long __init pplus_find_end_of_memory(void) +{ + unsigned long total; + + if (ppc_md.progress) + ppc_md.progress("pplus_find_end_of_memory", 0); + +#ifdef DUMP_DBATS + dump_dbats(); +#endif + + total = hawk_get_mem_size(PPLUS_HAWK_SMC_BASE); + return (total); +} + +static void __init pplus_map_io(void) +{ + io_block_mapping(PPLUS_ISA_IO_BASE, PPLUS_ISA_IO_BASE, 0x10000000, + _PAGE_IO); + io_block_mapping(0xfef80000, 0xfef80000, 0x00080000, _PAGE_IO); +} + +static void __init pplus_init2(void) +{ +#ifdef CONFIG_NVRAM + request_region(PREP_NVRAM_AS0, 0x8, "nvram"); +#endif + request_region(0x20, 0x20, "pic1"); + request_region(0xa0, 0x20, "pic2"); + request_region(0x00, 0x20, "dma1"); + request_region(0x40, 0x20, "timer"); + request_region(0x80, 0x10, "dma page reg"); + request_region(0xc0, 0x20, "dma2"); +} + +/* + * Set BAT 2 to access 0x8000000 so progress messages will work and set BAT 3 + * to 0xf0000000 to access Falcon/Raven or Hawk registers + */ +static __inline__ void pplus_set_bat(void) +{ + /* wait for all outstanding memory accesses to complete */ + mb(); + + /* setup DBATs */ + mtspr(SPRN_DBAT2U, 0x80001ffe); + mtspr(SPRN_DBAT2L, 0x8000002a); + mtspr(SPRN_DBAT3U, 0xf0001ffe); + mtspr(SPRN_DBAT3L, 0xf000002a); + + /* wait for updates */ + mb(); +} + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + parse_bootinfo(find_bootinfo()); + + /* Map in board regs, etc. */ + pplus_set_bat(); + + isa_io_base = PREP_ISA_IO_BASE; + isa_mem_base = PREP_ISA_MEM_BASE; + pci_dram_offset = PREP_PCI_DRAM_OFFSET; + ISA_DMA_THRESHOLD = 0x00ffffff; + DMA_MODE_READ = 0x44; + DMA_MODE_WRITE = 0x48; + + ppc_md.setup_arch = pplus_setup_arch; + ppc_md.show_cpuinfo = pplus_show_cpuinfo; + ppc_md.irq_canonicalize = pplus_irq_canonicalize; + ppc_md.init_IRQ = pplus_init_IRQ; + /* this gets changed later on if we have an OpenPIC -- Cort */ + ppc_md.get_irq = i8259_irq; + ppc_md.init = pplus_init2; + + ppc_md.restart = pplus_restart; + ppc_md.power_off = pplus_power_off; + ppc_md.halt = pplus_halt; + + TODC_INIT(TODC_TYPE_MK48T59, PREP_NVRAM_AS0, PREP_NVRAM_AS1, + PREP_NVRAM_DATA, 8); + + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.calibrate_decr = todc_calibrate_decr; + ppc_md.nvram_read_val = todc_m48txx_read_val; + ppc_md.nvram_write_val = todc_m48txx_write_val; + + ppc_md.find_end_of_memory = pplus_find_end_of_memory; + ppc_md.setup_io_mappings = pplus_map_io; + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) + ppc_ide_md.default_irq = pplus_ide_default_irq; + ppc_ide_md.default_io_base = pplus_ide_default_io_base; + ppc_ide_md.ide_init_hwif = pplus_ide_init_hwif_ports; +#endif + +#ifdef CONFIG_SERIAL_TEXT_DEBUG + ppc_md.progress = gen550_progress; +#endif /* CONFIG_SERIAL_TEXT_DEBUG */ +#ifdef CONFIG_KGDB + ppc_md.kgdb_map_scc = gen550_kgdb_map_scc; +#endif +#ifdef CONFIG_SMP + ppc_md.smp_ops = &pplus_smp_ops; +#endif /* CONFIG_SMP */ +} diff --git a/arch/ppc/platforms/pplus.h b/arch/ppc/platforms/pplus.h new file mode 100644 index 00000000000..90f0cb2d409 --- /dev/null +++ b/arch/ppc/platforms/pplus.h @@ -0,0 +1,67 @@ +/* + * arch/ppc/platforms/pplus.h + * + * Definitions for Motorola MCG Falcon/Raven & HAWK North Bridge & Memory ctlr. + * + * Author: Mark A. Greerinclude/asm-ppc/hawk.h + * mgreer@mvista.com + * + * Modified by Randy Vinson (rvinson@mvista.com) + * + * 2001-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. + */ + +#ifndef __PPC_PPLUS_H +#define __PPC_PPLUS_H + +#include <asm/io.h> + +/* + * Due to limiations imposed by legacy hardware (primaryily IDE controllers), + * the PPLUS boards operate using a PReP address map. + * + * From Processor (physical) -> PCI: + * PCI Mem Space: 0xc0000000 - 0xfe000000 -> 0x00000000 - 0x3e000000 (768 MB) + * PCI I/O Space: 0x80000000 - 0x90000000 -> 0x00000000 - 0x10000000 (256 MB) + * Note: Must skip 0xfe000000-0xfe400000 for CONFIG_HIGHMEM/PKMAP area + * + * From PCI -> Processor (physical): + * System Memory: 0x80000000 -> 0x00000000 + */ + +#define PPLUS_ISA_MEM_BASE PREP_ISA_MEM_BASE +#define PPLUS_ISA_IO_BASE PREP_ISA_IO_BASE + +/* PCI Memory space mapping info */ +#define PPLUS_PCI_MEM_SIZE 0x30000000U +#define PPLUS_PROC_PCI_MEM_START PPLUS_ISA_MEM_BASE +#define PPLUS_PROC_PCI_MEM_END (PPLUS_PROC_PCI_MEM_START + \ + PPLUS_PCI_MEM_SIZE - 1) +#define PPLUS_PCI_MEM_START 0x00000000U +#define PPLUS_PCI_MEM_END (PPLUS_PCI_MEM_START + \ + PPLUS_PCI_MEM_SIZE - 1) + +/* PCI I/O space mapping info */ +#define PPLUS_PCI_IO_SIZE 0x10000000U +#define PPLUS_PROC_PCI_IO_START PPLUS_ISA_IO_BASE +#define PPLUS_PROC_PCI_IO_END (PPLUS_PROC_PCI_IO_START + \ + PPLUS_PCI_IO_SIZE - 1) +#define PPLUS_PCI_IO_START 0x00000000U +#define PPLUS_PCI_IO_END (PPLUS_PCI_IO_START + \ + PPLUS_PCI_IO_SIZE - 1) +/* System memory mapping info */ +#define PPLUS_PCI_DRAM_OFFSET PREP_PCI_DRAM_OFFSET +#define PPLUS_PCI_PHY_MEM_OFFSET (PPLUS_ISA_MEM_BASE-PPLUS_PCI_MEM_START) + +/* Define base addresses for important sets of registers */ +#define PPLUS_HAWK_SMC_BASE 0xfef80000U +#define PPLUS_HAWK_PPC_REG_BASE 0xfeff0000U +#define PPLUS_SYS_CONFIG_REG 0xfef80400U +#define PPLUS_L2_CONTROL_REG 0x8000081cU + +#define PPLUS_VGA_MEM_BASE 0xf0000000U + +#endif /* __PPC_PPLUS_H */ diff --git a/arch/ppc/platforms/pq2ads.c b/arch/ppc/platforms/pq2ads.c new file mode 100644 index 00000000000..6a1475c1e12 --- /dev/null +++ b/arch/ppc/platforms/pq2ads.c @@ -0,0 +1,26 @@ +/* + * arch/ppc/platforms/pq2ads.c + * + * PQ2ADS platform support + * + * Author: Kumar Gala <kumar.gala@freescale.com> + * Derived from: est8260_setup.c by Allen Curtis + * + * Copyright 2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/init.h> + +#include <asm/mpc8260.h> + +void __init +m82xx_board_setup(void) +{ + /* Enable the 2nd UART port */ + *(volatile uint *)(BCSR_ADDR + 4) &= ~BCSR1_RS232_EN2; +} diff --git a/arch/ppc/platforms/pq2ads.h b/arch/ppc/platforms/pq2ads.h new file mode 100644 index 00000000000..cf5e5dd06d6 --- /dev/null +++ b/arch/ppc/platforms/pq2ads.h @@ -0,0 +1,96 @@ +/* + * A collection of structures, addresses, and values associated with + * the Motorola MPC8260ADS/MPC8266ADS-PCI boards. + * Copied from the RPX-Classic and SBS8260 stuff. + * + * Copyright (c) 2001 Dan Malek (dan@mvista.com) + */ +#ifdef __KERNEL__ +#ifndef __MACH_ADS8260_DEFS +#define __MACH_ADS8260_DEFS + +#include <linux/config.h> + +#include <asm/ppcboot.h> + +/* Memory map is configured by the PROM startup. + * We just map a few things we need. The CSR is actually 4 byte-wide + * registers that can be accessed as 8-, 16-, or 32-bit values. + */ +#define CPM_MAP_ADDR ((uint)0xf0000000) +#define BCSR_ADDR ((uint)0xf4500000) +#define BCSR_SIZE ((uint)(32 * 1024)) + +#define BOOTROM_RESTART_ADDR ((uint)0xff000104) + +/* For our show_cpuinfo hooks. */ +#define CPUINFO_VENDOR "Motorola" +#define CPUINFO_MACHINE "PQ2 ADS PowerPC" + +/* The ADS8260 has 16, 32-bit wide control/status registers, accessed + * only on word boundaries. + * Not all are used (yet), or are interesting to us (yet). + */ + +/* Things of interest in the CSR. +*/ +#define BCSR0_LED0 ((uint)0x02000000) /* 0 == on */ +#define BCSR0_LED1 ((uint)0x01000000) /* 0 == on */ +#define BCSR1_FETHIEN ((uint)0x08000000) /* 0 == enable */ +#define BCSR1_FETH_RST ((uint)0x04000000) /* 0 == reset */ +#define BCSR1_RS232_EN1 ((uint)0x02000000) /* 0 == enable */ +#define BCSR1_RS232_EN2 ((uint)0x01000000) /* 0 == enable */ +#define BCSR3_FETHIEN2 ((uint)0x10000000) /* 0 == enable */ +#define BCSR3_FETH2_RST ((uint)0x80000000) /* 0 == reset */ + +#define PHY_INTERRUPT SIU_INT_IRQ7 + +#ifdef CONFIG_PCI +/* PCI interrupt controller */ +#define PCI_INT_STAT_REG 0xF8200000 +#define PCI_INT_MASK_REG 0xF8200004 +#define PIRQA (NR_SIU_INTS + 0) +#define PIRQB (NR_SIU_INTS + 1) +#define PIRQC (NR_SIU_INTS + 2) +#define PIRQD (NR_SIU_INTS + 3) + +/* + * PCI memory map definitions for MPC8266ADS-PCI. + * + * processor view + * local address PCI address target + * 0x80000000-0x9FFFFFFF 0x80000000-0x9FFFFFFF PCI mem with prefetch + * 0xA0000000-0xBFFFFFFF 0xA0000000-0xBFFFFFFF PCI mem w/o prefetch + * 0xF4000000-0xF7FFFFFF 0x00000000-0x03FFFFFF PCI IO + * + * PCI master view + * local address PCI address target + * 0x00000000-0x1FFFFFFF 0x00000000-0x1FFFFFFF MPC8266 local memory + */ + +/* window for a PCI master to access MPC8266 memory */ +#define PCI_SLV_MEM_LOCAL 0x00000000 /* Local base */ +#define PCI_SLV_MEM_BUS 0x00000000 /* PCI base */ + +/* window for the processor to access PCI memory with prefetching */ +#define PCI_MSTR_MEM_LOCAL 0x80000000 /* Local base */ +#define PCI_MSTR_MEM_BUS 0x80000000 /* PCI base */ +#define PCI_MSTR_MEM_SIZE 0x20000000 /* 512MB */ + +/* window for the processor to access PCI memory without prefetching */ +#define PCI_MSTR_MEMIO_LOCAL 0xA0000000 /* Local base */ +#define PCI_MSTR_MEMIO_BUS 0xA0000000 /* PCI base */ +#define PCI_MSTR_MEMIO_SIZE 0x20000000 /* 512MB */ + +/* window for the processor to access PCI I/O */ +#define PCI_MSTR_IO_LOCAL 0xF4000000 /* Local base */ +#define PCI_MSTR_IO_BUS 0x00000000 /* PCI base */ +#define PCI_MSTR_IO_SIZE 0x04000000 /* 64MB */ + +#define _IO_BASE PCI_MSTR_IO_LOCAL +#define _ISA_MEM_BASE PCI_MSTR_MEMIO_LOCAL +#define PCI_DRAM_OFFSET PCI_SLV_MEM_BUS +#endif /* CONFIG_PCI */ + +#endif /* __MACH_ADS8260_DEFS */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/prep_pci.c b/arch/ppc/platforms/prep_pci.c new file mode 100644 index 00000000000..8cd80eb447b --- /dev/null +++ b/arch/ppc/platforms/prep_pci.c @@ -0,0 +1,1336 @@ +/* + * PReP pci functions. + * Originally by Gary Thomas + * rewritten and updated by Cort Dougan (cort@cs.nmt.edu) + * + * The motherboard routes/maps will disappear shortly. -- Cort + */ + +#include <linux/config.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/init.h> + +#include <asm/sections.h> +#include <asm/byteorder.h> +#include <asm/io.h> +#include <asm/ptrace.h> +#include <asm/prom.h> +#include <asm/pci-bridge.h> +#include <asm/residual.h> +#include <asm/irq.h> +#include <asm/machdep.h> +#include <asm/open_pic.h> + +extern void (*setup_ibm_pci)(char *irq_lo, char *irq_hi); + +/* Which PCI interrupt line does a given device [slot] use? */ +/* Note: This really should be two dimensional based in slot/pin used */ +static unsigned char *Motherboard_map; +unsigned char *Motherboard_map_name; + +/* How is the 82378 PIRQ mapping setup? */ +static unsigned char *Motherboard_routes; + +static void (*Motherboard_non0)(struct pci_dev *); + +static void Powerplus_Map_Non0(struct pci_dev *); + +/* Used for Motorola to store system config register */ +static unsigned long *ProcInfo; + +/* Tables for known hardware */ + +/* Motorola PowerStackII - Utah */ +static char Utah_pci_IRQ_map[23] __prepdata = +{ + 0, /* Slot 0 - unused */ + 0, /* Slot 1 - unused */ + 5, /* Slot 2 - SCSI - NCR825A */ + 0, /* Slot 3 - unused */ + 3, /* Slot 4 - Ethernet - DEC2114x */ + 0, /* Slot 5 - unused */ + 2, /* Slot 6 - PCI Card slot #1 */ + 3, /* Slot 7 - PCI Card slot #2 */ + 5, /* Slot 8 - PCI Card slot #3 */ + 5, /* Slot 9 - PCI Bridge */ + /* added here in case we ever support PCI bridges */ + /* Secondary PCI bus cards are at slot-9,6 & slot-9,7 */ + 0, /* Slot 10 - unused */ + 0, /* Slot 11 - unused */ + 5, /* Slot 12 - SCSI - NCR825A */ + 0, /* Slot 13 - unused */ + 3, /* Slot 14 - enet */ + 0, /* Slot 15 - unused */ + 2, /* Slot 16 - unused */ + 3, /* Slot 17 - unused */ + 5, /* Slot 18 - unused */ + 0, /* Slot 19 - unused */ + 0, /* Slot 20 - unused */ + 0, /* Slot 21 - unused */ + 0, /* Slot 22 - unused */ +}; + +static char Utah_pci_IRQ_routes[] __prepdata = +{ + 0, /* Line 0 - Unused */ + 9, /* Line 1 */ + 10, /* Line 2 */ + 11, /* Line 3 */ + 14, /* Line 4 */ + 15, /* Line 5 */ +}; + +/* Motorola PowerStackII - Omaha */ +/* no integrated SCSI or ethernet */ +static char Omaha_pci_IRQ_map[23] __prepdata = +{ + 0, /* Slot 0 - unused */ + 0, /* Slot 1 - unused */ + 3, /* Slot 2 - Winbond EIDE */ + 0, /* Slot 3 - unused */ + 0, /* Slot 4 - unused */ + 0, /* Slot 5 - unused */ + 1, /* Slot 6 - PCI slot 1 */ + 2, /* Slot 7 - PCI slot 2 */ + 3, /* Slot 8 - PCI slot 3 */ + 4, /* Slot 9 - PCI slot 4 */ /* needs indirect access */ + 0, /* Slot 10 - unused */ + 0, /* Slot 11 - unused */ + 0, /* Slot 12 - unused */ + 0, /* Slot 13 - unused */ + 0, /* Slot 14 - unused */ + 0, /* Slot 15 - unused */ + 1, /* Slot 16 - PCI slot 1 */ + 2, /* Slot 17 - PCI slot 2 */ + 3, /* Slot 18 - PCI slot 3 */ + 4, /* Slot 19 - PCI slot 4 */ /* needs indirect access */ + 0, + 0, + 0, +}; + +static char Omaha_pci_IRQ_routes[] __prepdata = +{ + 0, /* Line 0 - Unused */ + 9, /* Line 1 */ + 11, /* Line 2 */ + 14, /* Line 3 */ + 15 /* Line 4 */ +}; + +/* Motorola PowerStack */ +static char Blackhawk_pci_IRQ_map[19] __prepdata = +{ + 0, /* Slot 0 - unused */ + 0, /* Slot 1 - unused */ + 0, /* Slot 2 - unused */ + 0, /* Slot 3 - unused */ + 0, /* Slot 4 - unused */ + 0, /* Slot 5 - unused */ + 0, /* Slot 6 - unused */ + 0, /* Slot 7 - unused */ + 0, /* Slot 8 - unused */ + 0, /* Slot 9 - unused */ + 0, /* Slot 10 - unused */ + 0, /* Slot 11 - unused */ + 3, /* Slot 12 - SCSI */ + 0, /* Slot 13 - unused */ + 1, /* Slot 14 - Ethernet */ + 0, /* Slot 15 - unused */ + 1, /* Slot P7 */ + 2, /* Slot P6 */ + 3, /* Slot P5 */ +}; + +static char Blackhawk_pci_IRQ_routes[] __prepdata = +{ + 0, /* Line 0 - Unused */ + 9, /* Line 1 */ + 11, /* Line 2 */ + 15, /* Line 3 */ + 15 /* Line 4 */ +}; + +/* Motorola Mesquite */ +static char Mesquite_pci_IRQ_map[23] __prepdata = +{ + 0, /* Slot 0 - unused */ + 0, /* Slot 1 - unused */ + 0, /* Slot 2 - unused */ + 0, /* Slot 3 - unused */ + 0, /* Slot 4 - unused */ + 0, /* Slot 5 - unused */ + 0, /* Slot 6 - unused */ + 0, /* Slot 7 - unused */ + 0, /* Slot 8 - unused */ + 0, /* Slot 9 - unused */ + 0, /* Slot 10 - unused */ + 0, /* Slot 11 - unused */ + 0, /* Slot 12 - unused */ + 0, /* Slot 13 - unused */ + 2, /* Slot 14 - Ethernet */ + 0, /* Slot 15 - unused */ + 3, /* Slot 16 - PMC */ + 0, /* Slot 17 - unused */ + 0, /* Slot 18 - unused */ + 0, /* Slot 19 - unused */ + 0, /* Slot 20 - unused */ + 0, /* Slot 21 - unused */ + 0, /* Slot 22 - unused */ +}; + +/* Motorola Sitka */ +static char Sitka_pci_IRQ_map[21] __prepdata = +{ + 0, /* Slot 0 - unused */ + 0, /* Slot 1 - unused */ + 0, /* Slot 2 - unused */ + 0, /* Slot 3 - unused */ + 0, /* Slot 4 - unused */ + 0, /* Slot 5 - unused */ + 0, /* Slot 6 - unused */ + 0, /* Slot 7 - unused */ + 0, /* Slot 8 - unused */ + 0, /* Slot 9 - unused */ + 0, /* Slot 10 - unused */ + 0, /* Slot 11 - unused */ + 0, /* Slot 12 - unused */ + 0, /* Slot 13 - unused */ + 2, /* Slot 14 - Ethernet */ + 0, /* Slot 15 - unused */ + 9, /* Slot 16 - PMC 1 */ + 12, /* Slot 17 - PMC 2 */ + 0, /* Slot 18 - unused */ + 0, /* Slot 19 - unused */ + 4, /* Slot 20 - NT P2P bridge */ +}; + +/* Motorola MTX */ +static char MTX_pci_IRQ_map[23] __prepdata = +{ + 0, /* Slot 0 - unused */ + 0, /* Slot 1 - unused */ + 0, /* Slot 2 - unused */ + 0, /* Slot 3 - unused */ + 0, /* Slot 4 - unused */ + 0, /* Slot 5 - unused */ + 0, /* Slot 6 - unused */ + 0, /* Slot 7 - unused */ + 0, /* Slot 8 - unused */ + 0, /* Slot 9 - unused */ + 0, /* Slot 10 - unused */ + 0, /* Slot 11 - unused */ + 3, /* Slot 12 - SCSI */ + 0, /* Slot 13 - unused */ + 2, /* Slot 14 - Ethernet */ + 0, /* Slot 15 - unused */ + 9, /* Slot 16 - PCI/PMC slot 1 */ + 10, /* Slot 17 - PCI/PMC slot 2 */ + 11, /* Slot 18 - PCI slot 3 */ + 0, /* Slot 19 - unused */ + 0, /* Slot 20 - unused */ + 0, /* Slot 21 - unused */ + 0, /* Slot 22 - unused */ +}; + +/* Motorola MTX Plus */ +/* Secondary bus interrupt routing is not supported yet */ +static char MTXplus_pci_IRQ_map[23] __prepdata = +{ + 0, /* Slot 0 - unused */ + 0, /* Slot 1 - unused */ + 0, /* Slot 2 - unused */ + 0, /* Slot 3 - unused */ + 0, /* Slot 4 - unused */ + 0, /* Slot 5 - unused */ + 0, /* Slot 6 - unused */ + 0, /* Slot 7 - unused */ + 0, /* Slot 8 - unused */ + 0, /* Slot 9 - unused */ + 0, /* Slot 10 - unused */ + 0, /* Slot 11 - unused */ + 3, /* Slot 12 - SCSI */ + 0, /* Slot 13 - unused */ + 2, /* Slot 14 - Ethernet 1 */ + 0, /* Slot 15 - unused */ + 9, /* Slot 16 - PCI slot 1P */ + 10, /* Slot 17 - PCI slot 2P */ + 11, /* Slot 18 - PCI slot 3P */ + 10, /* Slot 19 - Ethernet 2 */ + 0, /* Slot 20 - P2P Bridge */ + 0, /* Slot 21 - unused */ + 0, /* Slot 22 - unused */ +}; + +static char Raven_pci_IRQ_routes[] __prepdata = +{ + 0, /* This is a dummy structure */ +}; + +/* Motorola MVME16xx */ +static char Genesis_pci_IRQ_map[16] __prepdata = +{ + 0, /* Slot 0 - unused */ + 0, /* Slot 1 - unused */ + 0, /* Slot 2 - unused */ + 0, /* Slot 3 - unused */ + 0, /* Slot 4 - unused */ + 0, /* Slot 5 - unused */ + 0, /* Slot 6 - unused */ + 0, /* Slot 7 - unused */ + 0, /* Slot 8 - unused */ + 0, /* Slot 9 - unused */ + 0, /* Slot 10 - unused */ + 0, /* Slot 11 - unused */ + 3, /* Slot 12 - SCSI */ + 0, /* Slot 13 - unused */ + 1, /* Slot 14 - Ethernet */ + 0, /* Slot 15 - unused */ +}; + +static char Genesis_pci_IRQ_routes[] __prepdata = +{ + 0, /* Line 0 - Unused */ + 10, /* Line 1 */ + 11, /* Line 2 */ + 14, /* Line 3 */ + 15 /* Line 4 */ +}; + +static char Genesis2_pci_IRQ_map[23] __prepdata = +{ + 0, /* Slot 0 - unused */ + 0, /* Slot 1 - unused */ + 0, /* Slot 2 - unused */ + 0, /* Slot 3 - unused */ + 0, /* Slot 4 - unused */ + 0, /* Slot 5 - unused */ + 0, /* Slot 6 - unused */ + 0, /* Slot 7 - unused */ + 0, /* Slot 8 - unused */ + 0, /* Slot 9 - unused */ + 0, /* Slot 10 - unused */ + 0, /* Slot 11 - IDE */ + 3, /* Slot 12 - SCSI */ + 5, /* Slot 13 - Universe PCI - VME Bridge */ + 2, /* Slot 14 - Ethernet */ + 0, /* Slot 15 - unused */ + 9, /* Slot 16 - PMC 1 */ + 12, /* Slot 17 - pci */ + 11, /* Slot 18 - pci */ + 10, /* Slot 19 - pci */ + 0, /* Slot 20 - pci */ + 0, /* Slot 21 - unused */ + 0, /* Slot 22 - unused */ +}; + +/* Motorola Series-E */ +static char Comet_pci_IRQ_map[23] __prepdata = +{ + 0, /* Slot 0 - unused */ + 0, /* Slot 1 - unused */ + 0, /* Slot 2 - unused */ + 0, /* Slot 3 - unused */ + 0, /* Slot 4 - unused */ + 0, /* Slot 5 - unused */ + 0, /* Slot 6 - unused */ + 0, /* Slot 7 - unused */ + 0, /* Slot 8 - unused */ + 0, /* Slot 9 - unused */ + 0, /* Slot 10 - unused */ + 0, /* Slot 11 - unused */ + 3, /* Slot 12 - SCSI */ + 0, /* Slot 13 - unused */ + 1, /* Slot 14 - Ethernet */ + 0, /* Slot 15 - unused */ + 1, /* Slot 16 - PCI slot 1 */ + 2, /* Slot 17 - PCI slot 2 */ + 3, /* Slot 18 - PCI slot 3 */ + 4, /* Slot 19 - PCI bridge */ + 0, + 0, + 0, +}; + +static char Comet_pci_IRQ_routes[] __prepdata = +{ + 0, /* Line 0 - Unused */ + 10, /* Line 1 */ + 11, /* Line 2 */ + 14, /* Line 3 */ + 15 /* Line 4 */ +}; + +/* Motorola Series-EX */ +static char Comet2_pci_IRQ_map[23] __prepdata = +{ + 0, /* Slot 0 - unused */ + 0, /* Slot 1 - unused */ + 3, /* Slot 2 - SCSI - NCR825A */ + 0, /* Slot 3 - unused */ + 1, /* Slot 4 - Ethernet - DEC2104X */ + 0, /* Slot 5 - unused */ + 1, /* Slot 6 - PCI slot 1 */ + 2, /* Slot 7 - PCI slot 2 */ + 3, /* Slot 8 - PCI slot 3 */ + 4, /* Slot 9 - PCI bridge */ + 0, /* Slot 10 - unused */ + 0, /* Slot 11 - unused */ + 3, /* Slot 12 - SCSI - NCR825A */ + 0, /* Slot 13 - unused */ + 1, /* Slot 14 - Ethernet - DEC2104X */ + 0, /* Slot 15 - unused */ + 1, /* Slot 16 - PCI slot 1 */ + 2, /* Slot 17 - PCI slot 2 */ + 3, /* Slot 18 - PCI slot 3 */ + 4, /* Slot 19 - PCI bridge */ + 0, + 0, + 0, +}; + +static char Comet2_pci_IRQ_routes[] __prepdata = +{ + 0, /* Line 0 - Unused */ + 10, /* Line 1 */ + 11, /* Line 2 */ + 14, /* Line 3 */ + 15, /* Line 4 */ +}; + +/* + * ibm 830 (and 850?). + * This is actually based on the Carolina motherboard + * -- Cort + */ +static char ibm8xx_pci_IRQ_map[23] __prepdata = { + 0, /* Slot 0 - unused */ + 0, /* Slot 1 - unused */ + 0, /* Slot 2 - unused */ + 0, /* Slot 3 - unused */ + 0, /* Slot 4 - unused */ + 0, /* Slot 5 - unused */ + 0, /* Slot 6 - unused */ + 0, /* Slot 7 - unused */ + 0, /* Slot 8 - unused */ + 0, /* Slot 9 - unused */ + 0, /* Slot 10 - unused */ + 0, /* Slot 11 - FireCoral */ + 4, /* Slot 12 - Ethernet PCIINTD# */ + 2, /* Slot 13 - PCI Slot #2 */ + 2, /* Slot 14 - S3 Video PCIINTD# */ + 0, /* Slot 15 - onboard SCSI (INDI) [1] */ + 3, /* Slot 16 - NCR58C810 RS6000 Only PCIINTC# */ + 0, /* Slot 17 - unused */ + 2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */ + 0, /* Slot 19 - unused */ + 0, /* Slot 20 - unused */ + 0, /* Slot 21 - unused */ + 2, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */ +}; + +static char ibm8xx_pci_IRQ_routes[] __prepdata = { + 0, /* Line 0 - unused */ + 15, /* Line 1 */ + 15, /* Line 2 */ + 15, /* Line 3 */ + 15, /* Line 4 */ +}; + +/* + * a 6015 ibm board + * -- Cort + */ +static char ibm6015_pci_IRQ_map[23] __prepdata = { + 0, /* Slot 0 - unused */ + 0, /* Slot 1 - unused */ + 0, /* Slot 2 - unused */ + 0, /* Slot 3 - unused */ + 0, /* Slot 4 - unused */ + 0, /* Slot 5 - unused */ + 0, /* Slot 6 - unused */ + 0, /* Slot 7 - unused */ + 0, /* Slot 8 - unused */ + 0, /* Slot 9 - unused */ + 0, /* Slot 10 - unused */ + 0, /* Slot 11 - */ + 1, /* Slot 12 - SCSI */ + 2, /* Slot 13 - */ + 2, /* Slot 14 - */ + 1, /* Slot 15 - */ + 1, /* Slot 16 - */ + 0, /* Slot 17 - */ + 2, /* Slot 18 - */ + 0, /* Slot 19 - */ + 0, /* Slot 20 - */ + 0, /* Slot 21 - */ + 2, /* Slot 22 - */ +}; + +static char ibm6015_pci_IRQ_routes[] __prepdata = { + 0, /* Line 0 - unused */ + 13, /* Line 1 */ + 15, /* Line 2 */ + 15, /* Line 3 */ + 15, /* Line 4 */ +}; + + +/* IBM Nobis and Thinkpad 850 */ +static char Nobis_pci_IRQ_map[23] __prepdata ={ + 0, /* Slot 0 - unused */ + 0, /* Slot 1 - unused */ + 0, /* Slot 2 - unused */ + 0, /* Slot 3 - unused */ + 0, /* Slot 4 - unused */ + 0, /* Slot 5 - unused */ + 0, /* Slot 6 - unused */ + 0, /* Slot 7 - unused */ + 0, /* Slot 8 - unused */ + 0, /* Slot 9 - unused */ + 0, /* Slot 10 - unused */ + 0, /* Slot 11 - unused */ + 3, /* Slot 12 - SCSI */ + 0, /* Slot 13 - unused */ + 0, /* Slot 14 - unused */ + 0, /* Slot 15 - unused */ +}; + +static char Nobis_pci_IRQ_routes[] __prepdata = { + 0, /* Line 0 - Unused */ + 13, /* Line 1 */ + 13, /* Line 2 */ + 13, /* Line 3 */ + 13 /* Line 4 */ +}; + +/* + * IBM RS/6000 43p/140 -- paulus + * XXX we should get all this from the residual data + */ +static char ibm43p_pci_IRQ_map[23] __prepdata = { + 0, /* Slot 0 - unused */ + 0, /* Slot 1 - unused */ + 0, /* Slot 2 - unused */ + 0, /* Slot 3 - unused */ + 0, /* Slot 4 - unused */ + 0, /* Slot 5 - unused */ + 0, /* Slot 6 - unused */ + 0, /* Slot 7 - unused */ + 0, /* Slot 8 - unused */ + 0, /* Slot 9 - unused */ + 0, /* Slot 10 - unused */ + 0, /* Slot 11 - FireCoral ISA bridge */ + 6, /* Slot 12 - Ethernet */ + 0, /* Slot 13 - openpic */ + 0, /* Slot 14 - unused */ + 0, /* Slot 15 - unused */ + 7, /* Slot 16 - NCR58C825a onboard scsi */ + 0, /* Slot 17 - unused */ + 2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */ + 0, /* Slot 19 - unused */ + 0, /* Slot 20 - unused */ + 0, /* Slot 21 - unused */ + 1, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */ +}; + +static char ibm43p_pci_IRQ_routes[] __prepdata = { + 0, /* Line 0 - unused */ + 15, /* Line 1 */ + 15, /* Line 2 */ + 15, /* Line 3 */ + 15, /* Line 4 */ +}; + +/* Motorola PowerPlus architecture PCI IRQ tables */ +/* Interrupt line values for INTA-D on primary/secondary MPIC inputs */ + +struct powerplus_irq_list +{ + unsigned char primary[4]; /* INT A-D */ + unsigned char secondary[4]; /* INT A-D */ +}; + +/* + * For standard PowerPlus boards, bus 0 PCI INTs A-D are routed to + * OpenPIC inputs 9-12. PCI INTs A-D from the on board P2P bridge + * are routed to OpenPIC inputs 5-8. These values are offset by + * 16 in the table to reflect the Linux kernel interrupt value. + */ +struct powerplus_irq_list Powerplus_pci_IRQ_list __prepdata = +{ + {25, 26, 27, 28}, + {21, 22, 23, 24} +}; + +/* + * For the MCP750 (system slot board), cPCI INTs A-D are routed to + * OpenPIC inputs 8-11 and the PMC INTs A-D are routed to OpenPIC + * input 3. On a hot swap MCP750, the companion card PCI INTs A-D + * are routed to OpenPIC inputs 12-15. These values are offset by + * 16 in the table to reflect the Linux kernel interrupt value. + */ +struct powerplus_irq_list Mesquite_pci_IRQ_list __prepdata = +{ + {24, 25, 26, 27}, + {28, 29, 30, 31} +}; + +/* + * This table represents the standard PCI swizzle defined in the + * PCI bus specification. + */ +static unsigned char prep_pci_intpins[4][4] __prepdata = +{ + { 1, 2, 3, 4}, /* Buses 0, 4, 8, ... */ + { 2, 3, 4, 1}, /* Buses 1, 5, 9, ... */ + { 3, 4, 1, 2}, /* Buses 2, 6, 10 ... */ + { 4, 1, 2, 3}, /* Buses 3, 7, 11 ... */ +}; + +/* We have to turn on LEVEL mode for changed IRQ's */ +/* All PCI IRQ's need to be level mode, so this should be something + * other than hard-coded as well... IRQ's are individually mappable + * to either edge or level. + */ + +/* + * 8259 edge/level control definitions + */ +#define ISA8259_M_ELCR 0x4d0 +#define ISA8259_S_ELCR 0x4d1 + +#define ELCRS_INT15_LVL 0x80 +#define ELCRS_INT14_LVL 0x40 +#define ELCRS_INT12_LVL 0x10 +#define ELCRS_INT11_LVL 0x08 +#define ELCRS_INT10_LVL 0x04 +#define ELCRS_INT9_LVL 0x02 +#define ELCRS_INT8_LVL 0x01 +#define ELCRM_INT7_LVL 0x80 +#define ELCRM_INT5_LVL 0x20 + +#if 0 +/* + * PCI config space access. + */ +#define CFGADDR(dev) ((1<<(dev>>3)) | ((dev&7)<<8)) +#define DEVNO(dev) (dev>>3) + +#define MIN_DEVNR 11 +#define MAX_DEVNR 22 + +static int __prep +prep_read_config(struct pci_bus *bus, unsigned int devfn, int offset, + int len, u32 *val) +{ + struct pci_controller *hose = bus->sysdata; + volatile void __iomem *cfg_data; + + if (bus->number != 0 || DEVNO(devfn) < MIN_DEVNR + || DEVNO(devfn) > MAX_DEVNR) + return PCIBIOS_DEVICE_NOT_FOUND; + + /* + * Note: the caller has already checked that offset is + * suitably aligned and that len is 1, 2 or 4. + */ + cfg_data = hose->cfg_data + CFGADDR(devfn) + offset; + switch (len) { + case 1: + *val = in_8(cfg_data); + break; + case 2: + *val = in_le16(cfg_data); + break; + default: + *val = in_le32(cfg_data); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static int __prep +prep_write_config(struct pci_bus *bus, unsigned int devfn, int offset, + int len, u32 val) +{ + struct pci_controller *hose = bus->sysdata; + volatile void __iomem *cfg_data; + + if (bus->number != 0 || DEVNO(devfn) < MIN_DEVNR + || DEVNO(devfn) > MAX_DEVNR) + return PCIBIOS_DEVICE_NOT_FOUND; + + /* + * Note: the caller has already checked that offset is + * suitably aligned and that len is 1, 2 or 4. + */ + cfg_data = hose->cfg_data + CFGADDR(devfn) + offset; + switch (len) { + case 1: + out_8(cfg_data, val); + break; + case 2: + out_le16(cfg_data, val); + break; + default: + out_le32(cfg_data, val); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops prep_pci_ops = +{ + prep_read_config, + prep_write_config +}; +#endif + +#define MOTOROLA_CPUTYPE_REG 0x800 +#define MOTOROLA_BASETYPE_REG 0x803 +#define MPIC_RAVEN_ID 0x48010000 +#define MPIC_HAWK_ID 0x48030000 +#define MOT_PROC2_BIT 0x800 + +static u_char prep_openpic_initsenses[] __initdata = { + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* MVME2600_INT_SIO */ + (IRQ_SENSE_EDGE | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_FALCN_ECC_ERR */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_ETHERNET */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_SCSI */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_GRAPHICS */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME3 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTA */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTB */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTC */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTD */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_LM_SIG0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_LM_SIG1 */ +}; + +#define MOT_RAVEN_PRESENT 0x1 +#define MOT_HAWK_PRESENT 0x2 + +int mot_entry = -1; +int prep_keybd_present = 1; +int MotMPIC; +int mot_multi; + +int __init +raven_init(void) +{ + unsigned int devid; + unsigned int pci_membase; + unsigned char base_mod; + + /* Check to see if the Raven chip exists. */ + if ( _prep_type != _PREP_Motorola) { + OpenPIC_Addr = NULL; + return 0; + } + + /* Check to see if this board is a type that might have a Raven. */ + if ((inb(MOTOROLA_CPUTYPE_REG) & 0xF0) != 0xE0) { + OpenPIC_Addr = NULL; + return 0; + } + + /* Check the first PCI device to see if it is a Raven. */ + early_read_config_dword(NULL, 0, 0, PCI_VENDOR_ID, &devid); + + switch (devid & 0xffff0000) { + case MPIC_RAVEN_ID: + MotMPIC = MOT_RAVEN_PRESENT; + break; + case MPIC_HAWK_ID: + MotMPIC = MOT_HAWK_PRESENT; + break; + default: + OpenPIC_Addr = NULL; + return 0; + } + + + /* Read the memory base register. */ + early_read_config_dword(NULL, 0, 0, PCI_BASE_ADDRESS_1, &pci_membase); + + if (pci_membase == 0) { + OpenPIC_Addr = NULL; + return 0; + } + + /* Map the Raven MPIC registers to virtual memory. */ + OpenPIC_Addr = ioremap(pci_membase+0xC0000000, 0x22000); + + OpenPIC_InitSenses = prep_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof(prep_openpic_initsenses); + + ppc_md.get_irq = openpic_get_irq; + + /* If raven is present on Motorola store the system config register + * for later use. + */ + ProcInfo = (unsigned long *)ioremap(0xfef80400, 4); + + /* Indicate to system if this is a multiprocessor board */ + if (!(*ProcInfo & MOT_PROC2_BIT)) { + mot_multi = 1; + } + + /* This is a hack. If this is a 2300 or 2400 mot board then there is + * no keyboard controller and we have to indicate that. + */ + base_mod = inb(MOTOROLA_BASETYPE_REG); + if ((MotMPIC == MOT_HAWK_PRESENT) || (base_mod == 0xF9) || + (base_mod == 0xFA) || (base_mod == 0xE1)) + prep_keybd_present = 0; + + return 1; +} + +struct mot_info { + int cpu_type; /* 0x100 mask assumes for Raven and Hawk boards that the level/edge are set */ + /* 0x200 if this board has a Hawk chip. */ + int base_type; + int max_cpu; /* ored with 0x80 if this board should be checked for multi CPU */ + const char *name; + unsigned char *map; + unsigned char *routes; + void (*map_non0_bus)(struct pci_dev *); /* For boards with more than bus 0 devices. */ + struct powerplus_irq_list *pci_irq_list; /* List of PCI MPIC inputs */ + unsigned char secondary_bridge_devfn; /* devfn of secondary bus transparent bridge */ +} mot_info[] __prepdata = { + {0x300, 0x00, 0x00, "MVME 2400", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, + {0x010, 0x00, 0x00, "Genesis", Genesis_pci_IRQ_map, Genesis_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00}, + {0x020, 0x00, 0x00, "Powerstack (Series E)", Comet_pci_IRQ_map, Comet_pci_IRQ_routes, NULL, NULL, 0x00}, + {0x040, 0x00, 0x00, "Blackhawk (Powerstack)", Blackhawk_pci_IRQ_map, Blackhawk_pci_IRQ_routes, NULL, NULL, 0x00}, + {0x050, 0x00, 0x00, "Omaha (PowerStack II Pro3000)", Omaha_pci_IRQ_map, Omaha_pci_IRQ_routes, NULL, NULL, 0x00}, + {0x060, 0x00, 0x00, "Utah (Powerstack II Pro4000)", Utah_pci_IRQ_map, Utah_pci_IRQ_routes, NULL, NULL, 0x00}, + {0x0A0, 0x00, 0x00, "Powerstack (Series EX)", Comet2_pci_IRQ_map, Comet2_pci_IRQ_routes, NULL, NULL, 0x00}, + {0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)", Mesquite_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Mesquite_pci_IRQ_list, 0xFF}, + {0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)", Sitka_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, + {0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC", Mesquite_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Mesquite_pci_IRQ_list, 0xC0}, + {0x1E0, 0xF6, 0x80, "MTX Plus", MTXplus_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xA0}, + {0x1E0, 0xF6, 0x81, "Dual MTX Plus", MTXplus_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xA0}, + {0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00}, + {0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00}, + {0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00}, + {0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00}, + {0x1E0, 0xF9, 0x00, "MVME 2300", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, + {0x1E0, 0xFA, 0x00, "MVME 2300SC/2600", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, + {0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, + {0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, + {0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00}, + {0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, + {0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, + {0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, + {0x1E0, 0xFF, 0x00, "MVME 1600-001 or 1600-011", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, + {0x000, 0x00, 0x00, "", NULL, NULL, NULL, NULL, 0x00} +}; + +void __init +ibm_prep_init(void) +{ + if (have_residual_data) { + u32 addr, real_addr, len, offset; + PPC_DEVICE *mpic; + PnP_TAG_PACKET *pkt; + + /* Use the PReP residual data to determine if an OpenPIC is + * present. If so, get the large vendor packet which will + * tell us the base address and length in memory. + * If we are successful, ioremap the memory area and set + * OpenPIC_Addr (this indicates that the OpenPIC was found). + */ + mpic = residual_find_device(-1, NULL, SystemPeripheral, + ProgrammableInterruptController, MPIC, 0); + if (!mpic) + return; + + pkt = PnP_find_large_vendor_packet(res->DevicePnPHeap + + mpic->AllocatedOffset, 9, 0); + + if (!pkt) + return; + +#define p pkt->L4_Pack.L4_Data.L4_PPCPack + if (p.PPCData[1] == 32) { + switch (p.PPCData[0]) { + case 1: offset = PREP_ISA_IO_BASE; break; + case 2: offset = PREP_ISA_MEM_BASE; break; + default: return; /* Not I/O or memory?? */ + } + } + else + return; /* Not a 32-bit address */ + + real_addr = ld_le32((unsigned int *) (p.PPCData + 4)); + if (real_addr == 0xffffffff) + return; + + /* Adjust address to be as seen by CPU */ + addr = real_addr + offset; + + len = ld_le32((unsigned int *) (p.PPCData + 12)); + if (!len) + return; +#undef p + OpenPIC_Addr = ioremap(addr, len); + ppc_md.get_irq = openpic_get_irq; + + OpenPIC_InitSenses = prep_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof(prep_openpic_initsenses); + + printk(KERN_INFO "MPIC at 0x%08x (0x%08x), length 0x%08x " + "mapped to 0x%p\n", addr, real_addr, len, OpenPIC_Addr); + } +} + +static void __init +ibm43p_pci_map_non0(struct pci_dev *dev) +{ + unsigned char intpin; + static unsigned char bridge_intrs[4] = { 3, 4, 5, 8 }; + + if (dev == NULL) + return; + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &intpin); + if (intpin < 1 || intpin > 4) + return; + intpin = (PCI_SLOT(dev->devfn) + intpin - 1) & 3; + dev->irq = openpic_to_irq(bridge_intrs[intpin]); + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); +} + +void __init +prep_residual_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi) +{ + if (have_residual_data) { + Motherboard_map_name = res->VitalProductData.PrintableModel; + Motherboard_map = NULL; + Motherboard_routes = NULL; + residual_irq_mask(irq_edge_mask_lo, irq_edge_mask_hi); + } +} + +void __init +prep_sandalfoot_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi) +{ + Motherboard_map_name = "IBM 6015/7020 (Sandalfoot/Sandalbow)"; + Motherboard_map = ibm6015_pci_IRQ_map; + Motherboard_routes = ibm6015_pci_IRQ_routes; + *irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */ + *irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */ +} + +void __init +prep_thinkpad_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi) +{ + Motherboard_map_name = "IBM Thinkpad 850/860"; + Motherboard_map = Nobis_pci_IRQ_map; + Motherboard_routes = Nobis_pci_IRQ_routes; + *irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */ + *irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */ +} + +void __init +prep_carolina_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi) +{ + Motherboard_map_name = "IBM 7248, PowerSeries 830/850 (Carolina)"; + Motherboard_map = ibm8xx_pci_IRQ_map; + Motherboard_routes = ibm8xx_pci_IRQ_routes; + *irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */ + *irq_edge_mask_hi = 0xA4; /* irq's 10, 13, 15 level-triggered */ +} + +void __init +prep_tiger1_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi) +{ + Motherboard_map_name = "IBM 43P-140 (Tiger1)"; + Motherboard_map = ibm43p_pci_IRQ_map; + Motherboard_routes = ibm43p_pci_IRQ_routes; + Motherboard_non0 = ibm43p_pci_map_non0; + *irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */ + *irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */ +} + +void __init +prep_route_pci_interrupts(void) +{ + unsigned char *ibc_pirq = (unsigned char *)0x80800860; + unsigned char *ibc_pcicon = (unsigned char *)0x80800840; + int i; + + if ( _prep_type == _PREP_Motorola) + { + unsigned short irq_mode; + unsigned char cpu_type; + unsigned char base_mod; + int entry; + + cpu_type = inb(MOTOROLA_CPUTYPE_REG) & 0xF0; + base_mod = inb(MOTOROLA_BASETYPE_REG); + + for (entry = 0; mot_info[entry].cpu_type != 0; entry++) { + if (mot_info[entry].cpu_type & 0x200) { /* Check for Hawk chip */ + if (!(MotMPIC & MOT_HAWK_PRESENT)) + continue; + } else { /* Check non hawk boards */ + if ((mot_info[entry].cpu_type & 0xff) != cpu_type) + continue; + + if (mot_info[entry].base_type == 0) { + mot_entry = entry; + break; + } + + if (mot_info[entry].base_type != base_mod) + continue; + } + + if (!(mot_info[entry].max_cpu & 0x80)) { + mot_entry = entry; + break; + } + + /* processor 1 not present and max processor zero indicated */ + if ((*ProcInfo & MOT_PROC2_BIT) && !(mot_info[entry].max_cpu & 0x7f)) { + mot_entry = entry; + break; + } + + /* processor 1 present and max processor zero indicated */ + if (!(*ProcInfo & MOT_PROC2_BIT) && (mot_info[entry].max_cpu & 0x7f)) { + mot_entry = entry; + break; + } + } + + if (mot_entry == -1) /* No particular cpu type found - assume Blackhawk */ + mot_entry = 3; + + Motherboard_map_name = (unsigned char *)mot_info[mot_entry].name; + Motherboard_map = mot_info[mot_entry].map; + Motherboard_routes = mot_info[mot_entry].routes; + Motherboard_non0 = mot_info[mot_entry].map_non0_bus; + + if (!(mot_info[entry].cpu_type & 0x100)) { + /* AJF adjust level/edge control according to routes */ + irq_mode = 0; + for (i = 1; i <= 4; i++) + irq_mode |= ( 1 << Motherboard_routes[i] ); + outb( irq_mode & 0xff, 0x4d0 ); + outb( (irq_mode >> 8) & 0xff, 0x4d1 ); + } + } else if ( _prep_type == _PREP_IBM ) { + unsigned char irq_edge_mask_lo, irq_edge_mask_hi; + unsigned short irq_edge_mask; + int i; + + setup_ibm_pci(&irq_edge_mask_lo, &irq_edge_mask_hi); + + outb(inb(0x04d0)|irq_edge_mask_lo, 0x4d0); /* primary 8259 */ + outb(inb(0x04d1)|irq_edge_mask_hi, 0x4d1); /* cascaded 8259 */ + + irq_edge_mask = (irq_edge_mask_hi << 8) | irq_edge_mask_lo; + for (i = 0; i < 16; ++i, irq_edge_mask >>= 1) + if (irq_edge_mask & 1) + irq_desc[i].status |= IRQ_LEVEL; + } else { + printk("No known machine pci routing!\n"); + return; + } + + /* Set up mapping from slots */ + if (Motherboard_routes) { + for (i = 1; i <= 4; i++) + ibc_pirq[i-1] = Motherboard_routes[i]; + + /* Enable PCI interrupts */ + *ibc_pcicon |= 0x20; + } +} + +void __init +prep_pib_init(void) +{ + unsigned char reg; + unsigned short short_reg; + + struct pci_dev *dev = NULL; + + if (( _prep_type == _PREP_Motorola) && (OpenPIC_Addr)) { + /* + * Perform specific configuration for the Via Tech or + * or Winbond PCI-ISA-Bridge part. + */ + if ((dev = pci_get_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_82C586_1, dev))) { + /* + * PPCBUG does not set the enable bits + * for the IDE device. Force them on here. + */ + pci_read_config_byte(dev, 0x40, ®); + + reg |= 0x03; /* IDE: Chip Enable Bits */ + pci_write_config_byte(dev, 0x40, reg); + } + if ((dev = pci_get_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_82C586_2, + dev)) && (dev->devfn = 0x5a)) { + /* Force correct USB interrupt */ + dev->irq = 11; + pci_write_config_byte(dev, + PCI_INTERRUPT_LINE, + dev->irq); + } + if ((dev = pci_get_device(PCI_VENDOR_ID_WINBOND, + PCI_DEVICE_ID_WINBOND_83C553, dev))) { + /* Clear PCI Interrupt Routing Control Register. */ + short_reg = 0x0000; + pci_write_config_word(dev, 0x44, short_reg); + if (OpenPIC_Addr){ + /* Route IDE interrupts to IRQ 14 */ + reg = 0xEE; + pci_write_config_byte(dev, 0x43, reg); + } + } + pci_dev_put(dev); + } + + if ((dev = pci_get_device(PCI_VENDOR_ID_WINBOND, + PCI_DEVICE_ID_WINBOND_82C105, dev))){ + if (OpenPIC_Addr){ + /* + * Disable LEGIRQ mode so PCI INTS are routed + * directly to the 8259 and enable both channels + */ + pci_write_config_dword(dev, 0x40, 0x10ff0033); + + /* Force correct IDE interrupt */ + dev->irq = 14; + pci_write_config_byte(dev, + PCI_INTERRUPT_LINE, + dev->irq); + } else { + /* Enable LEGIRQ for PCI INT -> 8259 IRQ routing */ + pci_write_config_dword(dev, 0x40, 0x10ff08a1); + } + } + pci_dev_put(dev); +} + +static void __init +Powerplus_Map_Non0(struct pci_dev *dev) +{ + struct pci_bus *pbus; /* Parent bus structure pointer */ + struct pci_dev *tdev = dev; /* Temporary device structure */ + unsigned int devnum; /* Accumulated device number */ + unsigned char intline; /* Linux interrupt value */ + unsigned char intpin; /* PCI interrupt pin */ + + /* Check for valid PCI dev pointer */ + if (dev == NULL) return; + + /* Initialize bridge IDSEL variable */ + devnum = PCI_SLOT(tdev->devfn); + + /* Read the interrupt pin of the device and adjust for indexing */ + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &intpin); + + /* If device doesn't request an interrupt, return */ + if ( (intpin < 1) || (intpin > 4) ) + return; + + intpin--; + + /* + * Walk up to bus 0, adjusting the interrupt pin for the standard + * PCI bus swizzle. + */ + do { + intpin = (prep_pci_intpins[devnum % 4][intpin]) - 1; + pbus = tdev->bus; /* up one level */ + tdev = pbus->self; + devnum = PCI_SLOT(tdev->devfn); + } while(tdev->bus->number); + + /* Use the primary interrupt inputs by default */ + intline = mot_info[mot_entry].pci_irq_list->primary[intpin]; + + /* + * If the board has secondary interrupt inputs, walk the bus and + * note the devfn of the bridge from bus 0. If it is the same as + * the devfn of the bus bridge with secondary inputs, use those. + * Otherwise, assume it's a PMC site and get the interrupt line + * value from the interrupt routing table. + */ + if (mot_info[mot_entry].secondary_bridge_devfn) { + pbus = dev->bus; + + while (pbus->primary != 0) + pbus = pbus->parent; + + if ((pbus->self)->devfn != 0xA0) { + if ((pbus->self)->devfn == mot_info[mot_entry].secondary_bridge_devfn) + intline = mot_info[mot_entry].pci_irq_list->secondary[intpin]; + else { + if ((char *)(mot_info[mot_entry].map) == (char *)Mesquite_pci_IRQ_map) + intline = mot_info[mot_entry].map[((pbus->self)->devfn)/8] + 16; + else { + int i; + for (i=0;i<3;i++) + intpin = (prep_pci_intpins[devnum % 4][intpin]) - 1; + intline = mot_info[mot_entry].pci_irq_list->primary[intpin]; + } + } + } + } + + /* Write calculated interrupt value to header and device list */ + dev->irq = intline; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, (u8)dev->irq); +} + +void __init +prep_pcibios_fixup(void) +{ + struct pci_dev *dev = NULL; + int irq; + int have_openpic = (OpenPIC_Addr != NULL); + + prep_route_pci_interrupts(); + + printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name); + + /* Iterate through all the PCI devices, setting the IRQ */ + for_each_pci_dev(dev) { + /* + * If we have residual data, then this is easy: query the + * residual data for the IRQ line allocated to the device. + * This works the same whether we have an OpenPic or not. + */ + if (have_residual_data) { + irq = residual_pcidev_irq(dev); + dev->irq = have_openpic ? openpic_to_irq(irq) : irq; + } + /* + * If we don't have residual data, then we need to use + * tables to determine the IRQ. The table organisation + * is different depending on whether there is an OpenPIC + * or not. The tables are only used for bus 0, so check + * this first. + */ + else if (dev->bus->number == 0) { + irq = Motherboard_map[PCI_SLOT(dev->devfn)]; + dev->irq = have_openpic ? openpic_to_irq(irq) + : Motherboard_routes[irq]; + } + /* + * Finally, if we don't have residual data and the bus is + * non-zero, use the callback (if provided) + */ + else { + if (Motherboard_non0 != NULL) + Motherboard_non0(dev); + + continue; + } + + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + } + + /* Setup the Winbond or Via PIB */ + prep_pib_init(); +} + +static void __init +prep_pcibios_after_init(void) +{ +#if 0 + struct pci_dev *dev; + + /* If there is a WD 90C, reset the IO BAR to 0x0 (it started that + * way, but the PCI layer relocated it because it thought 0x0 was + * invalid for a BAR). + * If you don't do this, the card's VGA base will be <IO BAR>+0xc0000 + * instead of 0xc0000. vgacon.c (for example) is completely unaware of + * this little quirk. + */ + dev = pci_get_device(PCI_VENDOR_ID_WD, PCI_DEVICE_ID_WD_90C, NULL); + if (dev) { + dev->resource[1].end -= dev->resource[1].start; + dev->resource[1].start = 0; + /* tell the hardware */ + pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0x0); + pci_dev_put(dev); + } +#endif +} + +static void __init +prep_init_resource(struct resource *res, unsigned long start, + unsigned long end, int flags) +{ + res->flags = flags; + res->start = start; + res->end = end; + res->name = "PCI host bridge"; + res->parent = NULL; + res->sibling = NULL; + res->child = NULL; +} + +void __init +prep_find_bridges(void) +{ + struct pci_controller* hose; + + hose = pcibios_alloc_controller(); + if (!hose) + return; + + hose->first_busno = 0; + hose->last_busno = 0xff; + hose->pci_mem_offset = PREP_ISA_MEM_BASE; + hose->io_base_phys = PREP_ISA_IO_BASE; + hose->io_base_virt = ioremap(PREP_ISA_IO_BASE, 0x800000); + prep_init_resource(&hose->io_resource, 0, 0x007fffff, IORESOURCE_IO); + prep_init_resource(&hose->mem_resources[0], 0xc0000000, 0xfeffffff, + IORESOURCE_MEM); + setup_indirect_pci(hose, PREP_ISA_IO_BASE + 0xcf8, + PREP_ISA_IO_BASE + 0xcfc); + + printk("PReP architecture\n"); + + if (have_residual_data) { + PPC_DEVICE *hostbridge; + + hostbridge = residual_find_device(PROCESSORDEVICE, NULL, + BridgeController, PCIBridge, -1, 0); + if (hostbridge && + ((hostbridge->DeviceId.Interface == PCIBridgeIndirect) || + (hostbridge->DeviceId.Interface == PCIBridgeRS6K))) { + PnP_TAG_PACKET * pkt; + pkt = PnP_find_large_vendor_packet( + res->DevicePnPHeap+hostbridge->AllocatedOffset, + 3, 0); + if(pkt) { +#define p pkt->L4_Pack.L4_Data.L4_PPCPack + setup_indirect_pci(hose, + ld_le32((unsigned *) (p.PPCData)), + ld_le32((unsigned *) (p.PPCData+8))); +#undef p + } else + setup_indirect_pci(hose, 0x80000cf8, 0x80000cfc); + } + } + + ppc_md.pcibios_fixup = prep_pcibios_fixup; + ppc_md.pcibios_after_init = prep_pcibios_after_init; +} diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c new file mode 100644 index 00000000000..bc926be9547 --- /dev/null +++ b/arch/ppc/platforms/prep_setup.c @@ -0,0 +1,1181 @@ +/* + * arch/ppc/platforms/setup.c + * + * Copyright (C) 1995 Linus Torvalds + * Adapted from 'alpha' version by Gary Thomas + * Modified by Cort Dougan (cort@cs.nmt.edu) + * + * Support for PReP (Motorola MTX/MVME) + * by Troy Benjegerdes (hozer@drgw.net) + */ + +/* + * bootup setup stuff.. + */ + +#include <linux/config.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/stddef.h> +#include <linux/unistd.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/user.h> +#include <linux/a.out.h> +#include <linux/tty.h> +#include <linux/major.h> +#include <linux/interrupt.h> +#include <linux/reboot.h> +#include <linux/init.h> +#include <linux/initrd.h> +#include <linux/ioport.h> +#include <linux/console.h> +#include <linux/timex.h> +#include <linux/pci.h> +#include <linux/ide.h> +#include <linux/seq_file.h> +#include <linux/root_dev.h> + +#include <asm/sections.h> +#include <asm/mmu.h> +#include <asm/processor.h> +#include <asm/residual.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/cache.h> +#include <asm/dma.h> +#include <asm/machdep.h> +#include <asm/mc146818rtc.h> +#include <asm/mk48t59.h> +#include <asm/prep_nvram.h> +#include <asm/raven.h> +#include <asm/vga.h> +#include <asm/time.h> +#include <asm/mpc10x.h> +#include <asm/i8259.h> +#include <asm/open_pic.h> +#include <asm/pci-bridge.h> +#include <asm/todc.h> + +TODC_ALLOC(); + +unsigned char ucSystemType; +unsigned char ucBoardRev; +unsigned char ucBoardRevMaj, ucBoardRevMin; + +extern unsigned char prep_nvram_read_val(int addr); +extern void prep_nvram_write_val(int addr, + unsigned char val); +extern unsigned char rs_nvram_read_val(int addr); +extern void rs_nvram_write_val(int addr, + unsigned char val); +extern void ibm_prep_init(void); + +extern void prep_find_bridges(void); + +int _prep_type; + +extern void prep_residual_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi); +extern void prep_sandalfoot_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi); +extern void prep_thinkpad_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi); +extern void prep_carolina_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi); +extern void prep_tiger1_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi); + + +#define cached_21 (((char *)(ppc_cached_irq_mask))[3]) +#define cached_A1 (((char *)(ppc_cached_irq_mask))[2]) + +/* for the mac fs */ +dev_t boot_dev; + +#ifdef CONFIG_SOUND_CS4232 +long ppc_cs4232_dma, ppc_cs4232_dma2; +#endif + +extern PTE *Hash, *Hash_end; +extern unsigned long Hash_size, Hash_mask; +extern int probingmem; +extern unsigned long loops_per_jiffy; + +#ifdef CONFIG_SOUND_CS4232 +EXPORT_SYMBOL(ppc_cs4232_dma); +EXPORT_SYMBOL(ppc_cs4232_dma2); +#endif + +/* useful ISA ports */ +#define PREP_SYSCTL 0x81c +/* present in the IBM reference design; possibly identical in Mot boxes: */ +#define PREP_IBM_SIMM_ID 0x803 /* SIMM size: 32 or 8 MiB */ +#define PREP_IBM_SIMM_PRESENCE 0x804 +#define PREP_IBM_EQUIPMENT 0x80c +#define PREP_IBM_L2INFO 0x80d +#define PREP_IBM_PM1 0x82a /* power management register 1 */ +#define PREP_IBM_PLANAR 0x852 /* planar ID - identifies the motherboard */ +#define PREP_IBM_DISP 0x8c0 /* 4-digit LED display */ + +/* Equipment Present Register masks: */ +#define PREP_IBM_EQUIPMENT_RESERVED 0x80 +#define PREP_IBM_EQUIPMENT_SCSIFUSE 0x40 +#define PREP_IBM_EQUIPMENT_L2_COPYBACK 0x08 +#define PREP_IBM_EQUIPMENT_L2_256 0x04 +#define PREP_IBM_EQUIPMENT_CPU 0x02 +#define PREP_IBM_EQUIPMENT_L2 0x01 + +/* planar ID values: */ +/* Sandalfoot/Sandalbow (6015/7020) */ +#define PREP_IBM_SANDALFOOT 0xfc +/* Woodfield, Thinkpad 850/860 (6042/7249) */ +#define PREP_IBM_THINKPAD 0xff /* planar ID unimplemented */ +/* PowerSeries 830/850 (6050/6070) */ +#define PREP_IBM_CAROLINA_IDE_0 0xf0 +#define PREP_IBM_CAROLINA_IDE_1 0xf1 +#define PREP_IBM_CAROLINA_IDE_2 0xf2 +#define PREP_IBM_CAROLINA_IDE_3 0xf3 +/* 7248-43P */ +#define PREP_IBM_CAROLINA_SCSI_0 0xf4 +#define PREP_IBM_CAROLINA_SCSI_1 0xf5 +#define PREP_IBM_CAROLINA_SCSI_2 0xf6 +#define PREP_IBM_CAROLINA_SCSI_3 0xf7 /* missing from Carolina Tech Spec */ +/* Tiger1 (7043-140) */ +#define PREP_IBM_TIGER1_133 0xd1 +#define PREP_IBM_TIGER1_166 0xd2 +#define PREP_IBM_TIGER1_180 0xd3 +#define PREP_IBM_TIGER1_xxx 0xd4 /* unknown, but probably exists */ +#define PREP_IBM_TIGER1_333 0xd5 /* missing from Tiger Tech Spec */ + +/* setup_ibm_pci: + * set Motherboard_map_name, Motherboard_map, Motherboard_routes. + * return 8259 edge/level masks. + */ +void (*setup_ibm_pci)(char *irq_lo, char *irq_hi); + +extern char *Motherboard_map_name; /* for use in *_cpuinfo */ + +/* + * As found in the PReP reference implementation. + * Used by Thinkpad, Sandalfoot (6015/7020), and all Motorola PReP. + */ +static void __init +prep_gen_enable_l2(void) +{ + outb(inb(PREP_SYSCTL) | 0x3, PREP_SYSCTL); +} + +/* Used by Carolina and Tiger1 */ +static void __init +prep_carolina_enable_l2(void) +{ + outb(inb(PREP_SYSCTL) | 0xc0, PREP_SYSCTL); +} + +/* cpuinfo code common to all IBM PReP */ +static void __prep +prep_ibm_cpuinfo(struct seq_file *m) +{ + unsigned int equip_reg = inb(PREP_IBM_EQUIPMENT); + + seq_printf(m, "machine\t\t: PReP %s\n", Motherboard_map_name); + + seq_printf(m, "upgrade cpu\t: "); + if (equip_reg & PREP_IBM_EQUIPMENT_CPU) { + seq_printf(m, "not "); + } + seq_printf(m, "present\n"); + + /* print info about the SCSI fuse */ + seq_printf(m, "scsi fuse\t: "); + if (equip_reg & PREP_IBM_EQUIPMENT_SCSIFUSE) + seq_printf(m, "ok"); + else + seq_printf(m, "bad"); + seq_printf(m, "\n"); + + /* print info about SIMMs */ + if (have_residual_data) { + int i; + seq_printf(m, "simms\t\t: "); + for (i = 0; (res->ActualNumMemories) && (i < MAX_MEMS); i++) { + if (res->Memories[i].SIMMSize != 0) + seq_printf(m, "%d:%ldMiB ", i, + (res->Memories[i].SIMMSize > 1024) ? + res->Memories[i].SIMMSize>>20 : + res->Memories[i].SIMMSize); + } + seq_printf(m, "\n"); + } +} + +static int __prep +prep_gen_cpuinfo(struct seq_file *m) +{ + prep_ibm_cpuinfo(m); + return 0; +} + +static int __prep +prep_sandalfoot_cpuinfo(struct seq_file *m) +{ + unsigned int equip_reg = inb(PREP_IBM_EQUIPMENT); + + prep_ibm_cpuinfo(m); + + /* report amount and type of L2 cache present */ + seq_printf(m, "L2 cache\t: "); + if (equip_reg & PREP_IBM_EQUIPMENT_L2) { + seq_printf(m, "not present"); + } else { + if (equip_reg & PREP_IBM_EQUIPMENT_L2_256) + seq_printf(m, "256KiB"); + else + seq_printf(m, "unknown size"); + + if (equip_reg & PREP_IBM_EQUIPMENT_L2_COPYBACK) + seq_printf(m, ", copy-back"); + else + seq_printf(m, ", write-through"); + } + seq_printf(m, "\n"); + + return 0; +} + +static int __prep +prep_thinkpad_cpuinfo(struct seq_file *m) +{ + unsigned int equip_reg = inb(PREP_IBM_EQUIPMENT); + char *cpubus_speed, *pci_speed; + + prep_ibm_cpuinfo(m); + + /* report amount and type of L2 cache present */ + seq_printf(m, "l2 cache\t: "); + if ((equip_reg & 0x1) == 0) { + switch ((equip_reg & 0xc) >> 2) { + case 0x0: + seq_printf(m, "128KiB look-aside 2-way write-through\n"); + break; + case 0x1: + seq_printf(m, "512KiB look-aside direct-mapped write-back\n"); + break; + case 0x2: + seq_printf(m, "256KiB look-aside 2-way write-through\n"); + break; + case 0x3: + seq_printf(m, "256KiB look-aside direct-mapped write-back\n"); + break; + } + } else { + seq_printf(m, "not present\n"); + } + + /* report bus speeds because we can */ + if ((equip_reg & 0x80) == 0) { + switch ((equip_reg & 0x30) >> 4) { + case 0x1: + cpubus_speed = "50"; + pci_speed = "25"; + break; + case 0x3: + cpubus_speed = "66"; + pci_speed = "33"; + break; + default: + cpubus_speed = "unknown"; + pci_speed = "unknown"; + break; + } + } else { + switch ((equip_reg & 0x30) >> 4) { + case 0x1: + cpubus_speed = "25"; + pci_speed = "25"; + break; + case 0x2: + cpubus_speed = "60"; + pci_speed = "30"; + break; + case 0x3: + cpubus_speed = "33"; + pci_speed = "33"; + break; + default: + cpubus_speed = "unknown"; + pci_speed = "unknown"; + break; + } + } + seq_printf(m, "60x bus\t\t: %sMHz\n", cpubus_speed); + seq_printf(m, "pci bus\t\t: %sMHz\n", pci_speed); + + return 0; +} + +static int __prep +prep_carolina_cpuinfo(struct seq_file *m) +{ + unsigned int equip_reg = inb(PREP_IBM_EQUIPMENT); + + prep_ibm_cpuinfo(m); + + /* report amount and type of L2 cache present */ + seq_printf(m, "l2 cache\t: "); + if ((equip_reg & 0x1) == 0) { + unsigned int l2_reg = inb(PREP_IBM_L2INFO); + + /* L2 size */ + if ((l2_reg & 0x60) == 0) + seq_printf(m, "256KiB"); + else if ((l2_reg & 0x60) == 0x20) + seq_printf(m, "512KiB"); + else + seq_printf(m, "unknown size"); + + /* L2 type */ + if ((l2_reg & 0x3) == 0) + seq_printf(m, ", async"); + else if ((l2_reg & 0x3) == 1) + seq_printf(m, ", sync"); + else + seq_printf(m, ", unknown type"); + + seq_printf(m, "\n"); + } else { + seq_printf(m, "not present\n"); + } + + return 0; +} + +static int __prep +prep_tiger1_cpuinfo(struct seq_file *m) +{ + unsigned int l2_reg = inb(PREP_IBM_L2INFO); + + prep_ibm_cpuinfo(m); + + /* report amount and type of L2 cache present */ + seq_printf(m, "l2 cache\t: "); + if ((l2_reg & 0xf) == 0xf) { + seq_printf(m, "not present\n"); + } else { + if (l2_reg & 0x8) + seq_printf(m, "async, "); + else + seq_printf(m, "sync burst, "); + + if (l2_reg & 0x4) + seq_printf(m, "parity, "); + else + seq_printf(m, "no parity, "); + + switch (l2_reg & 0x3) { + case 0x0: + seq_printf(m, "256KiB\n"); + break; + case 0x1: + seq_printf(m, "512KiB\n"); + break; + case 0x2: + seq_printf(m, "1MiB\n"); + break; + default: + seq_printf(m, "unknown size\n"); + break; + } + } + + return 0; +} + + +/* Used by all Motorola PReP */ +static int __prep +prep_mot_cpuinfo(struct seq_file *m) +{ + unsigned int cachew = *((unsigned char *)CACHECRBA); + + seq_printf(m, "machine\t\t: PReP %s\n", Motherboard_map_name); + + /* report amount and type of L2 cache present */ + seq_printf(m, "l2 cache\t: "); + switch (cachew & L2CACHE_MASK) { + case L2CACHE_512KB: + seq_printf(m, "512KiB"); + break; + case L2CACHE_256KB: + seq_printf(m, "256KiB"); + break; + case L2CACHE_1MB: + seq_printf(m, "1MiB"); + break; + case L2CACHE_NONE: + seq_printf(m, "none\n"); + goto no_l2; + break; + default: + seq_printf(m, "%x\n", cachew); + } + + seq_printf(m, ", parity %s", + (cachew & L2CACHE_PARITY)? "enabled" : "disabled"); + + seq_printf(m, " SRAM:"); + + switch ( ((cachew & 0xf0) >> 4) & ~(0x3) ) { + case 1: seq_printf(m, "synchronous, parity, flow-through\n"); + break; + case 2: seq_printf(m, "asynchronous, no parity\n"); + break; + case 3: seq_printf(m, "asynchronous, parity\n"); + break; + default:seq_printf(m, "synchronous, pipelined, no parity\n"); + break; + } + +no_l2: + /* print info about SIMMs */ + if (have_residual_data) { + int i; + seq_printf(m, "simms\t\t: "); + for (i = 0; (res->ActualNumMemories) && (i < MAX_MEMS); i++) { + if (res->Memories[i].SIMMSize != 0) + seq_printf(m, "%d:%ldM ", i, + (res->Memories[i].SIMMSize > 1024) ? + res->Memories[i].SIMMSize>>20 : + res->Memories[i].SIMMSize); + } + seq_printf(m, "\n"); + } + + return 0; +} + +static void __prep +prep_restart(char *cmd) +{ +#define PREP_SP92 0x92 /* Special Port 92 */ + local_irq_disable(); /* no interrupts */ + + /* set exception prefix high - to the prom */ + _nmask_and_or_msr(0, MSR_IP); + + /* make sure bit 0 (reset) is a 0 */ + outb( inb(PREP_SP92) & ~1L , PREP_SP92); + /* signal a reset to system control port A - soft reset */ + outb( inb(PREP_SP92) | 1 , PREP_SP92); + + while ( 1 ) ; + /* not reached */ +#undef PREP_SP92 +} + +static void __prep +prep_halt(void) +{ + local_irq_disable(); /* no interrupts */ + + /* set exception prefix high - to the prom */ + _nmask_and_or_msr(0, MSR_IP); + + while ( 1 ) ; + /* not reached */ +} + +/* Carrera is the power manager in the Thinkpads. Unfortunately not much is + * known about it, so we can't power down. + */ +static void __prep +prep_carrera_poweroff(void) +{ + prep_halt(); +} + +/* + * On most IBM PReP's, power management is handled by a Signetics 87c750 + * behind the Utah component on the ISA bus. To access the 750 you must write + * a series of nibbles to port 0x82a (decoded by the Utah). This is described + * somewhat in the IBM Carolina Technical Specification. + * -Hollis + */ +static void __prep +utah_sig87c750_setbit(unsigned int bytenum, unsigned int bitnum, int value) +{ + /* + * byte1: 0 0 0 1 0 d a5 a4 + * byte2: 0 0 0 1 a3 a2 a1 a0 + * + * d = the bit's value, enabled or disabled + * (a5 a4 a3) = the byte number, minus 20 + * (a2 a1 a0) = the bit number + * + * example: set the 5th bit of byte 21 (21.5) + * a5 a4 a3 = 001 (byte 1) + * a2 a1 a0 = 101 (bit 5) + * + * byte1 = 0001 0100 (0x14) + * byte2 = 0001 1101 (0x1d) + */ + unsigned char byte1=0x10, byte2=0x10; + + /* the 750's '20.0' is accessed as '0.0' through Utah (which adds 20) */ + bytenum -= 20; + + byte1 |= (!!value) << 2; /* set d */ + byte1 |= (bytenum >> 1) & 0x3; /* set a5, a4 */ + + byte2 |= (bytenum & 0x1) << 3; /* set a3 */ + byte2 |= bitnum & 0x7; /* set a2, a1, a0 */ + + outb(byte1, PREP_IBM_PM1); /* first nibble */ + mb(); + udelay(100); /* important: let controller recover */ + + outb(byte2, PREP_IBM_PM1); /* second nibble */ + mb(); + udelay(100); /* important: let controller recover */ +} + +static void __prep +prep_sig750_poweroff(void) +{ + /* tweak the power manager found in most IBM PRePs (except Thinkpads) */ + + local_irq_disable(); + /* set exception prefix high - to the prom */ + _nmask_and_or_msr(0, MSR_IP); + + utah_sig87c750_setbit(21, 5, 1); /* set bit 21.5, "PMEXEC_OFF" */ + + while (1) ; + /* not reached */ +} + +static int __prep +prep_show_percpuinfo(struct seq_file *m, int i) +{ + /* PREP's without residual data will give incorrect values here */ + seq_printf(m, "clock\t\t: "); + if (have_residual_data) + seq_printf(m, "%ldMHz\n", + (res->VitalProductData.ProcessorHz > 1024) ? + res->VitalProductData.ProcessorHz / 1000000 : + res->VitalProductData.ProcessorHz); + else + seq_printf(m, "???\n"); + + return 0; +} + +#ifdef CONFIG_SOUND_CS4232 +static long __init masktoint(unsigned int i) +{ + int t = -1; + while (i >> ++t) + ; + return (t-1); +} + +/* + * ppc_cs4232_dma and ppc_cs4232_dma2 are used in include/asm/dma.h + * to distinguish sound dma-channels from others. This is because + * blocksize on 16 bit dma-channels 5,6,7 is 128k, but + * the cs4232.c uses 64k like on 8 bit dma-channels 0,1,2,3 + */ + +static void __init prep_init_sound(void) +{ + PPC_DEVICE *audiodevice = NULL; + + /* + * Get the needed resource informations from residual data. + * + */ + if (have_residual_data) + audiodevice = residual_find_device(~0, NULL, + MultimediaController, AudioController, -1, 0); + + if (audiodevice != NULL) { + PnP_TAG_PACKET *pkt; + + pkt = PnP_find_packet((unsigned char *)&res->DevicePnPHeap[audiodevice->AllocatedOffset], + S5_Packet, 0); + if (pkt != NULL) + ppc_cs4232_dma = masktoint(pkt->S5_Pack.DMAMask); + pkt = PnP_find_packet((unsigned char*)&res->DevicePnPHeap[audiodevice->AllocatedOffset], + S5_Packet, 1); + if (pkt != NULL) + ppc_cs4232_dma2 = masktoint(pkt->S5_Pack.DMAMask); + } + + /* + * These are the PReP specs' defaults for the cs4231. We use these + * as fallback incase we don't have residual data. + * At least the IBM Thinkpad 850 with IDE DMA Channels at 6 and 7 + * will use the other values. + */ + if (audiodevice == NULL) { + switch (_prep_type) { + case _PREP_IBM: + ppc_cs4232_dma = 1; + ppc_cs4232_dma2 = -1; + break; + default: + ppc_cs4232_dma = 6; + ppc_cs4232_dma2 = 7; + } + } + + /* + * Find a way to push these informations to the cs4232 driver + * Give it out with printk, when not in cmd_line? + * Append it to cmd_line and saved_command_line? + * Format is cs4232=io,irq,dma,dma2 + */ +} +#endif /* CONFIG_SOUND_CS4232 */ + +/* + * Fill out screen_info according to the residual data. This allows us to use + * at least vesafb. + */ +static void __init +prep_init_vesa(void) +{ +#if (defined(CONFIG_FB_VGA16) || defined(CONFIG_FB_VGA16_MODULE) || \ + defined(CONFIG_FB_VESA)) + PPC_DEVICE *vgadev = NULL; + + if (have_residual_data) + vgadev = residual_find_device(~0, NULL, DisplayController, + SVGAController, -1, 0); + + if (vgadev != NULL) { + PnP_TAG_PACKET *pkt; + + pkt = PnP_find_large_vendor_packet( + (unsigned char *)&res->DevicePnPHeap[vgadev->AllocatedOffset], + 0x04, 0); /* 0x04 = Display Tag */ + if (pkt != NULL) { + unsigned char *ptr = (unsigned char *)pkt; + + if (ptr[4]) { + /* graphics mode */ + screen_info.orig_video_isVGA = VIDEO_TYPE_VLFB; + + screen_info.lfb_depth = ptr[4] * 8; + + screen_info.lfb_width = swab16(*(short *)(ptr+6)); + screen_info.lfb_height = swab16(*(short *)(ptr+8)); + screen_info.lfb_linelength = swab16(*(short *)(ptr+10)); + + screen_info.lfb_base = swab32(*(long *)(ptr+12)); + screen_info.lfb_size = swab32(*(long *)(ptr+20)) / 65536; + } + } + } +#endif +} + +/* + * Set DBAT 2 to access 0x80000000 so early progress messages will work + */ +static __inline__ void +prep_set_bat(void) +{ + /* wait for all outstanding memory access to complete */ + mb(); + + /* setup DBATs */ + mtspr(SPRN_DBAT2U, 0x80001ffe); + mtspr(SPRN_DBAT2L, 0x8000002a); + + /* wait for updates */ + mb(); +} + +/* + * IBM 3-digit status LED + */ +static unsigned int ibm_statusled_base __prepdata; + +static void __prep +ibm_statusled_progress(char *s, unsigned short hex); + +static int __prep +ibm_statusled_panic(struct notifier_block *dummy1, unsigned long dummy2, + void * dummy3) +{ + ibm_statusled_progress(NULL, 0x505); /* SOS */ + return NOTIFY_DONE; +} + +static struct notifier_block ibm_statusled_block __prepdata = { + ibm_statusled_panic, + NULL, + INT_MAX /* try to do it first */ +}; + +static void __prep +ibm_statusled_progress(char *s, unsigned short hex) +{ + static int notifier_installed; + /* + * Progress uses 4 digits and we have only 3. So, we map 0xffff to + * 0xfff for display switch off. Out of range values are mapped to + * 0xeff, as I'm told 0xf00 and above are reserved for hardware codes. + * Install the panic notifier when the display is first switched off. + */ + if (hex == 0xffff) { + hex = 0xfff; + if (!notifier_installed) { + ++notifier_installed; + notifier_chain_register(&panic_notifier_list, + &ibm_statusled_block); + } + } + else + if (hex > 0xfff) + hex = 0xeff; + + mb(); + outw(hex, ibm_statusled_base); +} + +static void __init +ibm_statusled_init(void) +{ + /* + * The IBM 3-digit LED display is specified in the residual data + * as an operator panel device, type "System Status LED". Find + * that device and determine its address. We validate all the + * other parameters on the off-chance another, similar device + * exists. + */ + if (have_residual_data) { + PPC_DEVICE *led; + PnP_TAG_PACKET *pkt; + + led = residual_find_device(~0, NULL, SystemPeripheral, + OperatorPanel, SystemStatusLED, 0); + if (!led) + return; + + pkt = PnP_find_packet((unsigned char *) + &res->DevicePnPHeap[led->AllocatedOffset], S8_Packet, 0); + if (!pkt) + return; + + if (pkt->S8_Pack.IOInfo != ISAAddr16bit) + return; + if (*(unsigned short *)pkt->S8_Pack.RangeMin != + *(unsigned short *)pkt->S8_Pack.RangeMax) + return; + if (pkt->S8_Pack.IOAlign != 2) + return; + if (pkt->S8_Pack.IONum != 2) + return; + + ibm_statusled_base = ld_le16((unsigned short *) + (pkt->S8_Pack.RangeMin)); + ppc_md.progress = ibm_statusled_progress; + } +} + +static void __init +prep_setup_arch(void) +{ + unsigned char reg; + int is_ide=0; + + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000; + + /* Lookup PCI host bridges */ + prep_find_bridges(); + + /* Set up floppy in PS/2 mode */ + outb(0x09, SIO_CONFIG_RA); + reg = inb(SIO_CONFIG_RD); + reg = (reg & 0x3F) | 0x40; + outb(reg, SIO_CONFIG_RD); + outb(reg, SIO_CONFIG_RD); /* Have to write twice to change! */ + + switch ( _prep_type ) + { + case _PREP_IBM: + reg = inb(PREP_IBM_PLANAR); + printk(KERN_INFO "IBM planar ID: %02x", reg); + switch (reg) { + case PREP_IBM_SANDALFOOT: + prep_gen_enable_l2(); + setup_ibm_pci = prep_sandalfoot_setup_pci; + ppc_md.power_off = prep_sig750_poweroff; + ppc_md.show_cpuinfo = prep_sandalfoot_cpuinfo; + break; + case PREP_IBM_THINKPAD: + prep_gen_enable_l2(); + setup_ibm_pci = prep_thinkpad_setup_pci; + ppc_md.power_off = prep_carrera_poweroff; + ppc_md.show_cpuinfo = prep_thinkpad_cpuinfo; + break; + default: + if (have_residual_data) { + prep_gen_enable_l2(); + setup_ibm_pci = prep_residual_setup_pci; + ppc_md.power_off = prep_halt; + ppc_md.show_cpuinfo = prep_gen_cpuinfo; + break; + } + else + printk(" - unknown! Assuming Carolina"); + /* fall through */ + case PREP_IBM_CAROLINA_IDE_0: + case PREP_IBM_CAROLINA_IDE_1: + case PREP_IBM_CAROLINA_IDE_2: + case PREP_IBM_CAROLINA_IDE_3: + is_ide = 1; + case PREP_IBM_CAROLINA_SCSI_0: + case PREP_IBM_CAROLINA_SCSI_1: + case PREP_IBM_CAROLINA_SCSI_2: + case PREP_IBM_CAROLINA_SCSI_3: + prep_carolina_enable_l2(); + setup_ibm_pci = prep_carolina_setup_pci; + ppc_md.power_off = prep_sig750_poweroff; + ppc_md.show_cpuinfo = prep_carolina_cpuinfo; + break; + case PREP_IBM_TIGER1_133: + case PREP_IBM_TIGER1_166: + case PREP_IBM_TIGER1_180: + case PREP_IBM_TIGER1_xxx: + case PREP_IBM_TIGER1_333: + prep_carolina_enable_l2(); + setup_ibm_pci = prep_tiger1_setup_pci; + ppc_md.power_off = prep_sig750_poweroff; + ppc_md.show_cpuinfo = prep_tiger1_cpuinfo; + break; + } + printk("\n"); + + /* default root device */ + if (is_ide) + ROOT_DEV = MKDEV(IDE0_MAJOR, 3); + else + ROOT_DEV = MKDEV(SCSI_DISK0_MAJOR, 3); + + break; + case _PREP_Motorola: + prep_gen_enable_l2(); + ppc_md.power_off = prep_halt; + ppc_md.show_cpuinfo = prep_mot_cpuinfo; + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_SDA2; +#endif + break; + } + + /* Read in NVRAM data */ + init_prep_nvram(); + + /* if no bootargs, look in NVRAM */ + if ( cmd_line[0] == '\0' ) { + char *bootargs; + bootargs = prep_nvram_get_var("bootargs"); + if (bootargs != NULL) { + strcpy(cmd_line, bootargs); + /* again.. */ + strcpy(saved_command_line, cmd_line); + } + } + +#ifdef CONFIG_SOUND_CS4232 + prep_init_sound(); +#endif /* CONFIG_SOUND_CS4232 */ + + prep_init_vesa(); + + switch (_prep_type) { + case _PREP_Motorola: + raven_init(); + break; + case _PREP_IBM: + ibm_prep_init(); + break; + } + +#ifdef CONFIG_VGA_CONSOLE + /* vgacon.c needs to know where we mapped IO memory in io_block_mapping() */ + vgacon_remap_base = 0xf0000000; + conswitchp = &vga_con; +#endif +} + +/* + * First, see if we can get this information from the residual data. + * This is important on some IBM PReP systems. If we cannot, we let the + * TODC code handle doing this. + */ +static void __init +prep_calibrate_decr(void) +{ + if (have_residual_data) { + unsigned long freq, divisor = 4; + + if ( res->VitalProductData.ProcessorBusHz ) { + freq = res->VitalProductData.ProcessorBusHz; + printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", + (freq/divisor)/1000000, + (freq/divisor)%1000000); + tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000); + tb_ticks_per_jiffy = freq / HZ / divisor; + } + } + else + todc_calibrate_decr(); +} + +static unsigned int __prep +prep_irq_canonicalize(u_int irq) +{ + if (irq == 2) + { + return 9; + } + else + { + return irq; + } +} + +static void __init +prep_init_IRQ(void) +{ + int i; + unsigned int pci_viddid, pci_did; + + if (OpenPIC_Addr != NULL) { + openpic_init(NUM_8259_INTERRUPTS); + /* We have a cascade on OpenPIC IRQ 0, Linux IRQ 16 */ + openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade", + i8259_irq); + } + for ( i = 0 ; i < NUM_8259_INTERRUPTS ; i++ ) + irq_desc[i].handler = &i8259_pic; + + if (have_residual_data) { + i8259_init(residual_isapic_addr()); + return; + } + + /* If we have a Raven PCI bridge or a Hawk PCI bridge / Memory + * controller, we poll (as they have a different int-ack address). */ + early_read_config_dword(NULL, 0, 0, PCI_VENDOR_ID, &pci_viddid); + pci_did = (pci_viddid & 0xffff0000) >> 16; + if (((pci_viddid & 0xffff) == PCI_VENDOR_ID_MOTOROLA) + && ((pci_did == PCI_DEVICE_ID_MOTOROLA_RAVEN) + || (pci_did == PCI_DEVICE_ID_MOTOROLA_HAWK))) + i8259_init(0); + else + /* PCI interrupt ack address given in section 6.1.8 of the + * PReP specification. */ + i8259_init(MPC10X_MAPA_PCI_INTACK_ADDR); +} + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +/* + * IDE stuff. + */ +static int __prep +prep_ide_default_irq(unsigned long base) +{ + switch (base) { + case 0x1f0: return 13; + case 0x170: return 13; + case 0x1e8: return 11; + case 0x168: return 10; + case 0xfff0: return 14; /* MCP(N)750 ide0 */ + case 0xffe0: return 15; /* MCP(N)750 ide1 */ + default: return 0; + } +} + +static unsigned long __prep +prep_ide_default_io_base(int index) +{ + switch (index) { + case 0: return 0x1f0; + case 1: return 0x170; + case 2: return 0x1e8; + case 3: return 0x168; + default: + return 0; + } +} +#endif + +#ifdef CONFIG_SMP +/* PReP (MTX) support */ +static int __init +smp_prep_probe(void) +{ + extern int mot_multi; + + if (mot_multi) { + openpic_request_IPIs(); + smp_hw_index[1] = 1; + return 2; + } + + return 1; +} + +static void __init +smp_prep_kick_cpu(int nr) +{ + *(unsigned long *)KERNELBASE = nr; + asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory"); + printk("CPU1 released, waiting\n"); +} + +static void __init +smp_prep_setup_cpu(int cpu_nr) +{ + if (OpenPIC_Addr) + do_openpic_setup_cpu(); +} + +static struct smp_ops_t prep_smp_ops __prepdata = { + smp_openpic_message_pass, + smp_prep_probe, + smp_prep_kick_cpu, + smp_prep_setup_cpu, + .give_timebase = smp_generic_give_timebase, + .take_timebase = smp_generic_take_timebase, +}; +#endif /* CONFIG_SMP */ + +/* + * Setup the bat mappings we're going to load that cover + * the io areas. RAM was mapped by mapin_ram(). + * -- Cort + */ +static void __init +prep_map_io(void) +{ + io_block_mapping(0x80000000, PREP_ISA_IO_BASE, 0x10000000, _PAGE_IO); + io_block_mapping(0xf0000000, PREP_ISA_MEM_BASE, 0x08000000, _PAGE_IO); +} + +static int __init +prep_request_io(void) +{ + if (_machine == _MACH_prep) { +#ifdef CONFIG_NVRAM + request_region(PREP_NVRAM_AS0, 0x8, "nvram"); +#endif + request_region(0x00,0x20,"dma1"); + request_region(0x40,0x20,"timer"); + request_region(0x80,0x10,"dma page reg"); + request_region(0xc0,0x20,"dma2"); + } + + return 0; +} + +device_initcall(prep_request_io); + +void __init +prep_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ +#ifdef CONFIG_PREP_RESIDUAL + /* make a copy of residual data */ + if ( r3 ) { + memcpy((void *)res,(void *)(r3+KERNELBASE), + sizeof(RESIDUAL)); + } +#endif + + isa_io_base = PREP_ISA_IO_BASE; + isa_mem_base = PREP_ISA_MEM_BASE; + pci_dram_offset = PREP_PCI_DRAM_OFFSET; + ISA_DMA_THRESHOLD = 0x00ffffff; + DMA_MODE_READ = 0x44; + DMA_MODE_WRITE = 0x48; + + /* figure out what kind of prep workstation we are */ + if (have_residual_data) { + if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) ) + _prep_type = _PREP_IBM; + else + _prep_type = _PREP_Motorola; + } + else { + /* assume motorola if no residual (netboot?) */ + _prep_type = _PREP_Motorola; + } + +#ifdef CONFIG_PREP_RESIDUAL + /* Switch off all residual data processing if the user requests it */ + if (strstr(cmd_line, "noresidual") != NULL) + res = NULL; +#endif + + /* Initialise progress early to get maximum benefit */ + prep_set_bat(); + ibm_statusled_init(); + + ppc_md.setup_arch = prep_setup_arch; + ppc_md.show_percpuinfo = prep_show_percpuinfo; + ppc_md.show_cpuinfo = NULL; /* set in prep_setup_arch() */ + ppc_md.irq_canonicalize = prep_irq_canonicalize; + ppc_md.init_IRQ = prep_init_IRQ; + /* this gets changed later on if we have an OpenPIC -- Cort */ + ppc_md.get_irq = i8259_irq; + + ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot; + + ppc_md.restart = prep_restart; + ppc_md.power_off = NULL; /* set in prep_setup_arch() */ + ppc_md.halt = prep_halt; + + ppc_md.nvram_read_val = prep_nvram_read_val; + ppc_md.nvram_write_val = prep_nvram_write_val; + + ppc_md.time_init = todc_time_init; + if (_prep_type == _PREP_IBM) { + ppc_md.rtc_read_val = todc_mc146818_read_val; + ppc_md.rtc_write_val = todc_mc146818_write_val; + TODC_INIT(TODC_TYPE_MC146818, RTC_PORT(0), NULL, RTC_PORT(1), + 8); + } else { + TODC_INIT(TODC_TYPE_MK48T59, PREP_NVRAM_AS0, PREP_NVRAM_AS1, + PREP_NVRAM_DATA, 8); + } + + ppc_md.calibrate_decr = prep_calibrate_decr; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + + ppc_md.setup_io_mappings = prep_map_io; + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) + ppc_ide_md.default_irq = prep_ide_default_irq; + ppc_ide_md.default_io_base = prep_ide_default_io_base; +#endif + +#ifdef CONFIG_SMP + ppc_md.smp_ops = &prep_smp_ops; +#endif /* CONFIG_SMP */ +} diff --git a/arch/ppc/platforms/prpmc750.c b/arch/ppc/platforms/prpmc750.c new file mode 100644 index 00000000000..c894e1ab593 --- /dev/null +++ b/arch/ppc/platforms/prpmc750.c @@ -0,0 +1,364 @@ +/* + * arch/ppc/platforms/prpmc750_setup.c + * + * Board setup routines for Motorola PrPMC750 + * + * Author: Matt Porter <mporter@mvista.com> + * + * 2001-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. + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/types.h> +#include <linux/major.h> +#include <linux/initrd.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/seq_file.h> +#include <linux/ide.h> +#include <linux/root_dev.h> +#include <linux/slab.h> + +#include <asm/byteorder.h> +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/machdep.h> +#include <asm/pci-bridge.h> +#include <asm/uaccess.h> +#include <asm/time.h> +#include <asm/open_pic.h> +#include <asm/bootinfo.h> +#include <asm/hawk.h> + +#include "prpmc750.h" + +extern unsigned long loops_per_jiffy; + +extern void gen550_progress(char *, unsigned short); + +static u_char prpmc750_openpic_initsenses[] __initdata = +{ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_HOSTINT0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_UART */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_DEBUGINT */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_HAWK_WDT */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_UNUSED */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_ABORT */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_HOSTINT1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_HOSTINT2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_HOSTINT3 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_PMC_INTA */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_PMC_INTB */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_PMC_INTC */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_PMC_INTD */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_UNUSED */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_UNUSED */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_UNUSED */ +}; + +/* + * Motorola PrPMC750/PrPMC800 in PrPMCBASE or PrPMC-Carrier + * Combined irq tables. Only Base has IDSEL 14, only Carrier has 21 and 22. + */ +static inline int +prpmc_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {12, 0, 0, 0}, /* IDSEL 14 - Ethernet, base */ + {0, 0, 0, 0}, /* IDSEL 15 - unused */ + {10, 11, 12, 9}, /* IDSEL 16 - PMC A1, PMC1 */ + {10, 11, 12, 9}, /* IDSEL 17 - PrPMC-A-B, PMC2-B */ + {11, 12, 9, 10}, /* IDSEL 18 - PMC A1-B, PMC1-B */ + {0, 0, 0, 0}, /* IDSEL 19 - unused */ + {9, 10, 11, 12}, /* IDSEL 20 - P2P Bridge */ + {11, 12, 9, 10}, /* IDSEL 21 - PMC A2, carrier */ + {12, 9, 10, 11}, /* IDSEL 22 - PMC A2-B, carrier */ + }; + const long min_idsel = 14, max_idsel = 22, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +}; + +static void __init prpmc750_pcibios_fixup(void) +{ + struct pci_dev *dev; + unsigned short wtmp; + + /* + * Kludge to clean up after PPC6BUG which doesn't + * configure the CL5446 VGA card. Also the + * resource subsystem doesn't fixup the + * PCI mem resources on the CL5446. + */ + if ((dev = pci_get_device(PCI_VENDOR_ID_CIRRUS, + PCI_DEVICE_ID_CIRRUS_5446, 0))) { + dev->resource[0].start += PRPMC750_PCI_PHY_MEM_OFFSET; + dev->resource[0].end += PRPMC750_PCI_PHY_MEM_OFFSET; + pci_read_config_word(dev, PCI_COMMAND, &wtmp); + pci_write_config_word(dev, PCI_COMMAND, wtmp | 3); + /* Enable Color mode in MISC reg */ + outb(0x03, 0x3c2); + /* Select DRAM config reg */ + outb(0x0f, 0x3c4); + /* Set proper DRAM config */ + outb(0xdf, 0x3c5); + pci_dev_put(dev); + } +} + +void __init prpmc750_find_bridges(void) +{ + struct pci_controller *hose; + + hose = pcibios_alloc_controller(); + if (!hose) + return; + + hose->first_busno = 0; + hose->last_busno = 0xff; + hose->io_base_virt = (void *)PRPMC750_ISA_IO_BASE; + hose->pci_mem_offset = PRPMC750_PCI_PHY_MEM_OFFSET; + + pci_init_resource(&hose->io_resource, + PRPMC750_PCI_IO_START, + PRPMC750_PCI_IO_END, + IORESOURCE_IO, "PCI host bridge"); + + pci_init_resource(&hose->mem_resources[0], + PRPMC750_PROC_PCI_MEM_START, + PRPMC750_PROC_PCI_MEM_END, + IORESOURCE_MEM, "PCI host bridge"); + + hose->io_space.start = PRPMC750_PCI_IO_START; + hose->io_space.end = PRPMC750_PCI_IO_END; + hose->mem_space.start = PRPMC750_PCI_MEM_START; + hose->mem_space.end = PRPMC750_PCI_MEM_END - HAWK_MPIC_SIZE; + + if (hawk_init(hose, PRPMC750_HAWK_PPC_REG_BASE, + PRPMC750_PROC_PCI_MEM_START, + PRPMC750_PROC_PCI_MEM_END - HAWK_MPIC_SIZE, + PRPMC750_PROC_PCI_IO_START, PRPMC750_PROC_PCI_IO_END, + PRPMC750_PROC_PCI_MEM_END - HAWK_MPIC_SIZE + 1) + != 0) { + printk(KERN_CRIT "Could not initialize host bridge\n"); + } + + hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); + + ppc_md.pcibios_fixup = prpmc750_pcibios_fixup; + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = prpmc_map_irq; +} +static int prpmc750_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "machine\t\t: PrPMC750\n"); + + return 0; +} + +static void __init prpmc750_setup_arch(void) +{ + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000 / HZ; + + /* Lookup PCI host bridges */ + prpmc750_find_bridges(); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_SDA2; +#endif + + OpenPIC_InitSenses = prpmc750_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof(prpmc750_openpic_initsenses); + + printk(KERN_INFO "Port by MontaVista Software, Inc. " + "(source@mvista.com)\n"); +} + +/* + * Compute the PrPMC750's bus speed using the baud clock as a + * reference. + */ +static unsigned long __init prpmc750_get_bus_speed(void) +{ + unsigned long tbl_start, tbl_end; + unsigned long current_state, old_state, bus_speed; + unsigned char lcr, dll, dlm; + int baud_divisor, count; + + /* Read the UART's baud clock divisor */ + lcr = readb(PRPMC750_SERIAL_0_LCR); + writeb(lcr | UART_LCR_DLAB, PRPMC750_SERIAL_0_LCR); + dll = readb(PRPMC750_SERIAL_0_DLL); + dlm = readb(PRPMC750_SERIAL_0_DLM); + writeb(lcr & ~UART_LCR_DLAB, PRPMC750_SERIAL_0_LCR); + baud_divisor = (dlm << 8) | dll; + + /* + * Use the baud clock divisor and base baud clock + * to determine the baud rate and use that as + * the number of baud clock edges we use for + * the time base sample. Make it half the baud + * rate. + */ + count = PRPMC750_BASE_BAUD / (baud_divisor * 16); + + /* Find the first edge of the baud clock */ + old_state = readb(PRPMC750_STATUS_REG) & PRPMC750_BAUDOUT_MASK; + do { + current_state = readb(PRPMC750_STATUS_REG) & + PRPMC750_BAUDOUT_MASK; + } while (old_state == current_state); + + old_state = current_state; + + /* Get the starting time base value */ + tbl_start = get_tbl(); + + /* + * Loop until we have found a number of edges equal + * to half the count (half the baud rate) + */ + do { + do { + current_state = readb(PRPMC750_STATUS_REG) & + PRPMC750_BAUDOUT_MASK; + } while (old_state == current_state); + old_state = current_state; + } while (--count); + + /* Get the ending time base value */ + tbl_end = get_tbl(); + + /* Compute bus speed */ + bus_speed = (tbl_end - tbl_start) * 128; + + return bus_speed; +} + +static void __init prpmc750_calibrate_decr(void) +{ + unsigned long freq; + int divisor = 4; + + freq = prpmc750_get_bus_speed(); + + tb_ticks_per_jiffy = freq / (HZ * divisor); + tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000); +} + +static void prpmc750_restart(char *cmd) +{ + local_irq_disable(); + writeb(PRPMC750_MODRST_MASK, PRPMC750_MODRST_REG); + while (1) ; +} + +static void prpmc750_halt(void) +{ + local_irq_disable(); + while (1) ; +} + +static void prpmc750_power_off(void) +{ + prpmc750_halt(); +} + +static void __init prpmc750_init_IRQ(void) +{ + openpic_init(0); +} + +/* + * Set BAT 3 to map 0xf0000000 to end of physical memory space. + */ +static __inline__ void prpmc750_set_bat(void) +{ + mb(); + mtspr(SPRN_DBAT1U, 0xf0001ffe); + mtspr(SPRN_DBAT1L, 0xf000002a); + mb(); +} + +/* + * We need to read the Falcon/Hawk memory controller + * to properly determine this value + */ +static unsigned long __init prpmc750_find_end_of_memory(void) +{ + /* Read the memory size from the Hawk SMC */ + return hawk_get_mem_size(PRPMC750_HAWK_SMC_BASE); +} + +static void __init prpmc750_map_io(void) +{ + io_block_mapping(PRPMC750_ISA_IO_BASE, PRPMC750_ISA_IO_BASE, + 0x10000000, _PAGE_IO); +#if 0 + io_block_mapping(0xf0000000, 0xc0000000, 0x08000000, _PAGE_IO); +#endif + io_block_mapping(0xf8000000, 0xf8000000, 0x08000000, _PAGE_IO); +} + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + parse_bootinfo(find_bootinfo()); + + /* Cover the Hawk registers with a BAT */ + prpmc750_set_bat(); + + isa_io_base = PRPMC750_ISA_IO_BASE; + isa_mem_base = PRPMC750_ISA_MEM_BASE; + pci_dram_offset = PRPMC750_PCI_DRAM_OFFSET; + + ppc_md.setup_arch = prpmc750_setup_arch; + ppc_md.show_cpuinfo = prpmc750_show_cpuinfo; + ppc_md.init_IRQ = prpmc750_init_IRQ; + ppc_md.get_irq = openpic_get_irq; + + ppc_md.find_end_of_memory = prpmc750_find_end_of_memory; + ppc_md.setup_io_mappings = prpmc750_map_io; + + ppc_md.restart = prpmc750_restart; + ppc_md.power_off = prpmc750_power_off; + ppc_md.halt = prpmc750_halt; + + /* PrPMC750 has no timekeeper part */ + ppc_md.time_init = NULL; + ppc_md.get_rtc_time = NULL; + ppc_md.set_rtc_time = NULL; + ppc_md.calibrate_decr = prpmc750_calibrate_decr; + +#ifdef CONFIG_SERIAL_TEXT_DEBUG + ppc_md.progress = gen550_progress; +#endif /* CONFIG_SERIAL_TEXT_DEBUG */ +} diff --git a/arch/ppc/platforms/prpmc750.h b/arch/ppc/platforms/prpmc750.h new file mode 100644 index 00000000000..015b4f52c3e --- /dev/null +++ b/arch/ppc/platforms/prpmc750.h @@ -0,0 +1,95 @@ +/* + * include/asm-ppc/platforms/prpmc750.h + * + * Definitions for Motorola PrPMC750 board support + * + * Author: Matt Porter <mporter@mvista.com> + * + * 2001-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. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_PRPMC750_H__ +#define __ASM_PRPMC750_H__ + +/* + * Due to limiations imposed by legacy hardware (primaryily IDE controllers), + * the PrPMC750 carrier board operates using a PReP address map. + * + * From Processor (physical) -> PCI: + * PCI Mem Space: 0xc0000000 - 0xfe000000 -> 0x00000000 - 0x3e000000 (768 MB) + * PCI I/O Space: 0x80000000 - 0x90000000 -> 0x00000000 - 0x10000000 (256 MB) + * Note: Must skip 0xfe000000-0xfe400000 for CONFIG_HIGHMEM/PKMAP area + * + * From PCI -> Processor (physical): + * System Memory: 0x80000000 -> 0x00000000 + */ + +#define PRPMC750_ISA_IO_BASE PREP_ISA_IO_BASE +#define PRPMC750_ISA_MEM_BASE PREP_ISA_MEM_BASE + +/* PCI Memory space mapping info */ +#define PRPMC750_PCI_MEM_SIZE 0x30000000U +#define PRPMC750_PROC_PCI_MEM_START PRPMC750_ISA_MEM_BASE +#define PRPMC750_PROC_PCI_MEM_END (PRPMC750_PROC_PCI_MEM_START + \ + PRPMC750_PCI_MEM_SIZE - 1) +#define PRPMC750_PCI_MEM_START 0x00000000U +#define PRPMC750_PCI_MEM_END (PRPMC750_PCI_MEM_START + \ + PRPMC750_PCI_MEM_SIZE - 1) + +/* PCI I/O space mapping info */ +#define PRPMC750_PCI_IO_SIZE 0x10000000U +#define PRPMC750_PROC_PCI_IO_START PRPMC750_ISA_IO_BASE +#define PRPMC750_PROC_PCI_IO_END (PRPMC750_PROC_PCI_IO_START + \ + PRPMC750_PCI_IO_SIZE - 1) +#define PRPMC750_PCI_IO_START 0x00000000U +#define PRPMC750_PCI_IO_END (PRPMC750_PCI_IO_START + \ + PRPMC750_PCI_IO_SIZE - 1) + +/* System memory mapping info */ +#define PRPMC750_PCI_DRAM_OFFSET PREP_PCI_DRAM_OFFSET +#define PRPMC750_PCI_PHY_MEM_OFFSET (PRPMC750_ISA_MEM_BASE-PRPMC750_PCI_MEM_START) + +/* Register address definitions */ +#define PRPMC750_HAWK_SMC_BASE 0xfef80000U +#define PRPMC750_HAWK_PPC_REG_BASE 0xfeff0000U + +#define PRPMC750_BASE_BAUD 1843200 +#define PRPMC750_SERIAL_0 0xfef88000 +#define PRPMC750_SERIAL_0_DLL (PRPMC750_SERIAL_0 + (UART_DLL << 4)) +#define PRPMC750_SERIAL_0_DLM (PRPMC750_SERIAL_0 + (UART_DLM << 4)) +#define PRPMC750_SERIAL_0_LCR (PRPMC750_SERIAL_0 + (UART_LCR << 4)) + +#define PRPMC750_STATUS_REG 0xfef88080 +#define PRPMC750_BAUDOUT_MASK 0x02 +#define PRPMC750_MONARCH_MASK 0x01 + +#define PRPMC750_MODRST_REG 0xfef880a0 +#define PRPMC750_MODRST_MASK 0x01 + +#define PRPMC750_PIRQ_REG 0xfef880b0 +#define PRPMC750_SEL1_MASK 0x02 +#define PRPMC750_SEL0_MASK 0x01 + +#define PRPMC750_TBEN_REG 0xfef880c0 +#define PRPMC750_TBEN_MASK 0x01 + +/* UART Defines. */ +#define RS_TABLE_SIZE 4 + +/* Rate for the 1.8432 Mhz clock for the onboard serial chip */ +#define BASE_BAUD (PRPMC750_BASE_BAUD / 16) + +#define STD_COM_FLAGS ASYNC_BOOT_AUTOCONF + +#define SERIAL_PORT_DFNS \ + { 0, BASE_BAUD, PRPMC750_SERIAL_0, 1, STD_COM_FLAGS, \ + iomem_base: (unsigned char *)PRPMC750_SERIAL_0, \ + iomem_reg_shift: 4, \ + io_type: SERIAL_IO_MEM } /* ttyS0 */ + +#endif /* __ASM_PRPMC750_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/prpmc800.c b/arch/ppc/platforms/prpmc800.c new file mode 100644 index 00000000000..8b09fa69b35 --- /dev/null +++ b/arch/ppc/platforms/prpmc800.c @@ -0,0 +1,477 @@ +/* + * arch/ppc/platforms/prpmc800.c + * + * Author: Dale Farnsworth <dale.farnsworth@mvista.com> + * + * 2001-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. + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/types.h> +#include <linux/major.h> +#include <linux/initrd.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/seq_file.h> +#include <linux/ide.h> +#include <linux/root_dev.h> +#include <linux/harrier_defs.h> + +#include <asm/byteorder.h> +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/machdep.h> +#include <asm/time.h> +#include <asm/pci-bridge.h> +#include <asm/open_pic.h> +#include <asm/bootinfo.h> +#include <asm/harrier.h> + +#include "prpmc800.h" + +#define HARRIER_REVI_REG (PRPMC800_HARRIER_XCSR_BASE+HARRIER_REVI_OFF) +#define HARRIER_UCTL_REG (PRPMC800_HARRIER_XCSR_BASE+HARRIER_UCTL_OFF) +#define HARRIER_MISC_CSR_REG (PRPMC800_HARRIER_XCSR_BASE+HARRIER_MISC_CSR_OFF) +#define HARRIER_IFEVP_REG (PRPMC800_HARRIER_MPIC_BASE+HARRIER_MPIC_IFEVP_OFF) +#define HARRIER_IFEDE_REG (PRPMC800_HARRIER_MPIC_BASE+HARRIER_MPIC_IFEDE_OFF) +#define HARRIER_FEEN_REG (PRPMC800_HARRIER_XCSR_BASE+HARRIER_FEEN_OFF) +#define HARRIER_FEMA_REG (PRPMC800_HARRIER_XCSR_BASE+HARRIER_FEMA_OFF) + +#define HARRIER_VENI_REG (PRPMC800_HARRIER_XCSR_BASE + HARRIER_VENI_OFF) +#define HARRIER_MISC_CSR (PRPMC800_HARRIER_XCSR_BASE + \ + HARRIER_MISC_CSR_OFF) + +#define MONARCH (monarch != 0) +#define NON_MONARCH (monarch == 0) + +extern int mpic_init(void); +extern unsigned long loops_per_jiffy; +extern void gen550_progress(char *, unsigned short); + +static int monarch = 0; +static int found_self = 0; +static int self = 0; + +static u_char prpmc800_openpic_initsenses[] __initdata = +{ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_HOSTINT0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_UNUSED */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_DEBUGINT */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_HARRIER_WDT */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_UNUSED */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_UNUSED */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_HOSTINT1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_HOSTINT2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_HOSTINT3 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_PMC_INTA */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_PMC_INTB */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_PMC_INTC */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_PMC_INTD */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_UNUSED */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_UNUSED */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_UNUSED */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_HARRIER_INT (UARTS, ABORT, DMA) */ +}; + +/* + * Motorola PrPMC750/PrPMC800 in PrPMCBASE or PrPMC-Carrier + * Combined irq tables. Only Base has IDSEL 14, only Carrier has 21 and 22. + */ +static inline int +prpmc_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {12, 0, 0, 0}, /* IDSEL 14 - Ethernet, base */ + {0, 0, 0, 0}, /* IDSEL 15 - unused */ + {10, 11, 12, 9}, /* IDSEL 16 - PMC A1, PMC1 */ + {10, 11, 12, 9}, /* IDSEL 17 - PrPMC-A-B, PMC2-B */ + {11, 12, 9, 10}, /* IDSEL 18 - PMC A1-B, PMC1-B */ + {0, 0, 0, 0}, /* IDSEL 19 - unused */ + {9, 10, 11, 12}, /* IDSEL 20 - P2P Bridge */ + {11, 12, 9, 10}, /* IDSEL 21 - PMC A2, carrier */ + {12, 9, 10, 11}, /* IDSEL 22 - PMC A2-B, carrier */ + }; + const long min_idsel = 14, max_idsel = 22, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +}; + +static int +prpmc_read_config_dword(struct pci_controller *hose, u8 bus, u8 devfn, + int offset, u32 * val) +{ + /* paranoia */ + if ((hose == NULL) || + (hose->cfg_addr == NULL) || (hose->cfg_data == NULL)) + return PCIBIOS_DEVICE_NOT_FOUND; + + out_be32(hose->cfg_addr, ((offset & 0xfc) << 24) | (devfn << 16) + | ((bus - hose->bus_offset) << 8) | 0x80); + *val = in_le32((u32 *) (hose->cfg_data + (offset & 3))); + + return PCIBIOS_SUCCESSFUL; +} + +#define HARRIER_PCI_VEND_DEV_ID (PCI_VENDOR_ID_MOTOROLA | \ + (PCI_DEVICE_ID_MOTOROLA_HARRIER << 16)) +static int prpmc_self(u8 bus, u8 devfn) +{ + /* + * Harriers always view themselves as being on bus 0. If we're not + * looking at bus 0, we're not going to find ourselves. + */ + if (bus != 0) + return PCIBIOS_DEVICE_NOT_FOUND; + else { + int result; + int val; + struct pci_controller *hose; + + hose = pci_bus_to_hose(bus); + + /* See if target device is a Harrier */ + result = prpmc_read_config_dword(hose, bus, devfn, + PCI_VENDOR_ID, &val); + if ((result != PCIBIOS_SUCCESSFUL) || + (val != HARRIER_PCI_VEND_DEV_ID)) + return PCIBIOS_DEVICE_NOT_FOUND; + + /* + * LBA bit is set if target Harrier == initiating Harrier + * (i.e. if we are reading our own PCI header). + */ + result = prpmc_read_config_dword(hose, bus, devfn, + HARRIER_LBA_OFF, &val); + if ((result != PCIBIOS_SUCCESSFUL) || + ((val & HARRIER_LBA_MSK) != HARRIER_LBA_MSK)) + return PCIBIOS_DEVICE_NOT_FOUND; + + /* It's us, save our location for later */ + self = devfn; + found_self = 1; + return PCIBIOS_SUCCESSFUL; + } +} + +static int prpmc_exclude_device(u8 bus, u8 devfn) +{ + /* + * Monarch is allowed to access all PCI devices. Non-monarch is + * only allowed to access its own Harrier. + */ + + if (MONARCH) + return PCIBIOS_SUCCESSFUL; + if (found_self) + if ((bus == 0) && (devfn == self)) + return PCIBIOS_SUCCESSFUL; + else + return PCIBIOS_DEVICE_NOT_FOUND; + else + return prpmc_self(bus, devfn); +} + +void __init prpmc800_find_bridges(void) +{ + struct pci_controller *hose; + int host_bridge; + + hose = pcibios_alloc_controller(); + if (!hose) + return; + + hose->first_busno = 0; + hose->last_busno = 0xff; + + ppc_md.pci_exclude_device = prpmc_exclude_device; + ppc_md.pcibios_fixup = NULL; + ppc_md.pcibios_fixup_bus = NULL; + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = prpmc_map_irq; + + setup_indirect_pci(hose, + PRPMC800_PCI_CONFIG_ADDR, PRPMC800_PCI_CONFIG_DATA); + + /* Get host bridge vendor/dev id */ + + host_bridge = in_be32((uint *) (HARRIER_VENI_REG)); + + if (host_bridge != HARRIER_VEND_DEV_ID) { + printk(KERN_CRIT "Host bridge 0x%x not supported\n", + host_bridge); + return; + } + + monarch = in_be32((uint *) HARRIER_MISC_CSR) & HARRIER_SYSCON; + + printk(KERN_INFO "Running as %s.\n", + MONARCH ? "Monarch" : "Non-Monarch"); + + hose->io_space.start = PRPMC800_PCI_IO_START; + hose->io_space.end = PRPMC800_PCI_IO_END; + hose->io_base_virt = (void *)PRPMC800_ISA_IO_BASE; + hose->pci_mem_offset = PRPMC800_PCI_PHY_MEM_OFFSET; + + pci_init_resource(&hose->io_resource, + PRPMC800_PCI_IO_START, PRPMC800_PCI_IO_END, + IORESOURCE_IO, "PCI host bridge"); + + if (MONARCH) { + hose->mem_space.start = PRPMC800_PCI_MEM_START; + hose->mem_space.end = PRPMC800_PCI_MEM_END; + + pci_init_resource(&hose->mem_resources[0], + PRPMC800_PCI_MEM_START, + PRPMC800_PCI_MEM_END, + IORESOURCE_MEM, "PCI host bridge"); + + if (harrier_init(hose, + PRPMC800_HARRIER_XCSR_BASE, + PRPMC800_PROC_PCI_MEM_START, + PRPMC800_PROC_PCI_MEM_END, + PRPMC800_PROC_PCI_IO_START, + PRPMC800_PROC_PCI_IO_END, + PRPMC800_HARRIER_MPIC_BASE) != 0) + printk(KERN_CRIT "Could not initialize HARRIER " + "bridge\n"); + + harrier_release_eready(PRPMC800_HARRIER_XCSR_BASE); + harrier_wait_eready(PRPMC800_HARRIER_XCSR_BASE); + hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); + + } else { + pci_init_resource(&hose->mem_resources[0], + PRPMC800_NM_PCI_MEM_START, + PRPMC800_NM_PCI_MEM_END, + IORESOURCE_MEM, "PCI host bridge"); + + hose->mem_space.start = PRPMC800_NM_PCI_MEM_START; + hose->mem_space.end = PRPMC800_NM_PCI_MEM_END; + + if (harrier_init(hose, + PRPMC800_HARRIER_XCSR_BASE, + PRPMC800_NM_PROC_PCI_MEM_START, + PRPMC800_NM_PROC_PCI_MEM_END, + PRPMC800_PROC_PCI_IO_START, + PRPMC800_PROC_PCI_IO_END, + PRPMC800_HARRIER_MPIC_BASE) != 0) + printk(KERN_CRIT "Could not initialize HARRIER " + "bridge\n"); + + harrier_setup_nonmonarch(PRPMC800_HARRIER_XCSR_BASE, + HARRIER_ITSZ_1MB); + harrier_release_eready(PRPMC800_HARRIER_XCSR_BASE); + } +} + +static int prpmc800_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "machine\t\t: PrPMC800\n"); + + return 0; +} + +static void __init prpmc800_setup_arch(void) +{ + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000 / HZ; + + /* Lookup PCI host bridges */ + prpmc800_find_bridges(); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_SDA2; +#endif + + printk(KERN_INFO "Port by MontaVista Software, Inc. " + "(source@mvista.com)\n"); +} + +/* + * Compute the PrPMC800's tbl frequency using the baud clock as a reference. + */ +static void __init prpmc800_calibrate_decr(void) +{ + unsigned long tbl_start, tbl_end; + unsigned long current_state, old_state, tb_ticks_per_second; + unsigned int count; + unsigned int harrier_revision; + + harrier_revision = readb(HARRIER_REVI_REG); + if (harrier_revision < 2) { + /* XTAL64 was broken in harrier revision 1 */ + printk(KERN_INFO "time_init: Harrier revision %d, assuming " + "100 Mhz bus\n", harrier_revision); + tb_ticks_per_second = 100000000 / 4; + tb_ticks_per_jiffy = tb_ticks_per_second / HZ; + tb_to_us = mulhwu_scale_factor(tb_ticks_per_second, 1000000); + return; + } + + /* + * The XTAL64 bit oscillates at the 1/64 the base baud clock + * Set count to XTAL64 cycles per second. Since we'll count + * half-cycles, we'll reach the count in half a second. + */ + count = PRPMC800_BASE_BAUD / 64; + + /* Find the first edge of the baud clock */ + old_state = readb(HARRIER_UCTL_REG) & HARRIER_XTAL64_MASK; + do { + current_state = readb(HARRIER_UCTL_REG) & HARRIER_XTAL64_MASK; + } while (old_state == current_state); + + old_state = current_state; + + /* Get the starting time base value */ + tbl_start = get_tbl(); + + /* + * Loop until we have found a number of edges (half-cycles) + * equal to the count (half a second) + */ + do { + do { + current_state = readb(HARRIER_UCTL_REG) & + HARRIER_XTAL64_MASK; + } while (old_state == current_state); + old_state = current_state; + } while (--count); + + /* Get the ending time base value */ + tbl_end = get_tbl(); + + /* We only counted for half a second, so double to get ticks/second */ + tb_ticks_per_second = (tbl_end - tbl_start) * 2; + tb_ticks_per_jiffy = tb_ticks_per_second / HZ; + tb_to_us = mulhwu_scale_factor(tb_ticks_per_second, 1000000); +} + +static void prpmc800_restart(char *cmd) +{ + ulong temp; + + local_irq_disable(); + temp = in_be32((uint *) HARRIER_MISC_CSR_REG); + temp |= HARRIER_RSTOUT; + out_be32((uint *) HARRIER_MISC_CSR_REG, temp); + while (1) ; +} + +static void prpmc800_halt(void) +{ + local_irq_disable(); + while (1) ; +} + +static void prpmc800_power_off(void) +{ + prpmc800_halt(); +} + +static void __init prpmc800_init_IRQ(void) +{ + OpenPIC_InitSenses = prpmc800_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof(prpmc800_openpic_initsenses); + + /* Setup external interrupt sources. */ + openpic_set_sources(0, 16, OpenPIC_Addr + 0x10000); + /* Setup internal UART interrupt source. */ + openpic_set_sources(16, 1, OpenPIC_Addr + 0x10200); + + /* Do the MPIC initialization based on the above settings. */ + openpic_init(0); + + /* enable functional exceptions for uarts and abort */ + out_8((u8 *) HARRIER_FEEN_REG, (HARRIER_FE_UA0 | HARRIER_FE_UA1)); + out_8((u8 *) HARRIER_FEMA_REG, ~(HARRIER_FE_UA0 | HARRIER_FE_UA1)); +} + +/* + * Set BAT 3 to map 0xf0000000 to end of physical memory space. + */ +static __inline__ void prpmc800_set_bat(void) +{ + mb(); + mtspr(SPRN_DBAT1U, 0xf0001ffe); + mtspr(SPRN_DBAT1L, 0xf000002a); + mb(); +} + +/* + * We need to read the Harrier memory controller + * to properly determine this value + */ +static unsigned long __init prpmc800_find_end_of_memory(void) +{ + /* Read the memory size from the Harrier XCSR */ + return harrier_get_mem_size(PRPMC800_HARRIER_XCSR_BASE); +} + +static void __init prpmc800_map_io(void) +{ + io_block_mapping(0x80000000, 0x80000000, 0x10000000, _PAGE_IO); + io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO); +} + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + parse_bootinfo(find_bootinfo()); + + prpmc800_set_bat(); + + isa_io_base = PRPMC800_ISA_IO_BASE; + isa_mem_base = PRPMC800_ISA_MEM_BASE; + pci_dram_offset = PRPMC800_PCI_DRAM_OFFSET; + + ppc_md.setup_arch = prpmc800_setup_arch; + ppc_md.show_cpuinfo = prpmc800_show_cpuinfo; + ppc_md.init_IRQ = prpmc800_init_IRQ; + ppc_md.get_irq = openpic_get_irq; + + ppc_md.find_end_of_memory = prpmc800_find_end_of_memory; + ppc_md.setup_io_mappings = prpmc800_map_io; + + ppc_md.restart = prpmc800_restart; + ppc_md.power_off = prpmc800_power_off; + ppc_md.halt = prpmc800_halt; + + /* PrPMC800 has no timekeeper part */ + ppc_md.time_init = NULL; + ppc_md.get_rtc_time = NULL; + ppc_md.set_rtc_time = NULL; + ppc_md.calibrate_decr = prpmc800_calibrate_decr; +#ifdef CONFIG_SERIAL_TEXT_DEBUG + ppc_md.progress = gen550_progress; +#else /* !CONFIG_SERIAL_TEXT_DEBUG */ + ppc_md.progress = NULL; +#endif /* CONFIG_SERIAL_TEXT_DEBUG */ +} diff --git a/arch/ppc/platforms/prpmc800.h b/arch/ppc/platforms/prpmc800.h new file mode 100644 index 00000000000..e53ec9b42a3 --- /dev/null +++ b/arch/ppc/platforms/prpmc800.h @@ -0,0 +1,82 @@ +/* + * include/asm-ppc/platforms/prpmc800.h + * + * Definitions for Motorola PrPMC800 board support + * + * Author: Dale Farnsworth <dale.farnsworth@mvista.com> + * + * 2001-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. + */ + /* + * From Processor to PCI: + * PCI Mem Space: 0x80000000 - 0xa0000000 -> 0x80000000 - 0xa0000000 (512 MB) + * PCI I/O Space: 0xfe400000 - 0xfeef0000 -> 0x00000000 - 0x00b00000 (11 MB) + * Note: Must skip 0xfe000000-0xfe400000 for CONFIG_HIGHMEM/PKMAP area + * + * From PCI to Processor: + * System Memory: 0x00000000 -> 0x00000000 + */ + +#ifndef __ASMPPC_PRPMC800_H +#define __ASMPPC_PRPMC800_H + +#define PRPMC800_PCI_CONFIG_ADDR 0xfe000cf8 +#define PRPMC800_PCI_CONFIG_DATA 0xfe000cfc + +#define PRPMC800_PROC_PCI_IO_START 0xfe400000U +#define PRPMC800_PROC_PCI_IO_END 0xfeefffffU +#define PRPMC800_PCI_IO_START 0x00000000U +#define PRPMC800_PCI_IO_END 0x00afffffU + +#define PRPMC800_PROC_PCI_MEM_START 0x80000000U +#define PRPMC800_PROC_PCI_MEM_END 0x9fffffffU +#define PRPMC800_PCI_MEM_START 0x80000000U +#define PRPMC800_PCI_MEM_END 0x9fffffffU + +#define PRPMC800_NM_PROC_PCI_MEM_START 0x40000000U +#define PRPMC800_NM_PROC_PCI_MEM_END 0xdfffffffU +#define PRPMC800_NM_PCI_MEM_START 0x40000000U +#define PRPMC800_NM_PCI_MEM_END 0xdfffffffU + +#define PRPMC800_PCI_DRAM_OFFSET 0x00000000U +#define PRPMC800_PCI_PHY_MEM_OFFSET 0x00000000U + +#define PRPMC800_ISA_IO_BASE PRPMC800_PROC_PCI_IO_START +#define PRPMC800_ISA_MEM_BASE 0x00000000U + +#define PRPMC800_HARRIER_XCSR_BASE HARRIER_DEFAULT_XCSR_BASE +#define PRPMC800_HARRIER_MPIC_BASE 0xff000000 + +#define PRPMC800_SERIAL_1 0xfeff00c0 + +#define PRPMC800_BASE_BAUD 1843200 + +/* + * interrupt vector number and priority for harrier internal interrupt + * sources + */ +#define PRPMC800_INT_IRQ 16 +#define PRPMC800_INT_PRI 15 + +/* UART Defines. */ +#define RS_TABLE_SIZE 4 + +/* Rate for the 1.8432 Mhz clock for the onboard serial chip */ +#define BASE_BAUD (PRPMC800_BASE_BAUD / 16) + +#define STD_COM_FLAGS ASYNC_BOOT_AUTOCONF + +/* UARTS are at IRQ 16 */ +#define STD_SERIAL_PORT_DFNS \ + { 0, BASE_BAUD, PRPMC800_SERIAL_1, 16, STD_COM_FLAGS, /* ttyS0 */\ + iomem_base: (unsigned char *)PRPMC800_SERIAL_1, \ + iomem_reg_shift: 0, \ + io_type: SERIAL_IO_MEM }, + +#define SERIAL_PORT_DFNS \ + STD_SERIAL_PORT_DFNS + +#endif /* __ASMPPC_PRPMC800_H */ diff --git a/arch/ppc/platforms/radstone_ppc7d.c b/arch/ppc/platforms/radstone_ppc7d.c new file mode 100644 index 00000000000..2a99b43737a --- /dev/null +++ b/arch/ppc/platforms/radstone_ppc7d.c @@ -0,0 +1,1452 @@ +/* + * arch/ppc/platforms/radstone_ppc7d.c + * + * Board setup routines for the Radstone PPC7D boards. + * + * Author: James Chapman <jchapman@katalix.com> + * + * Based on code done by Rabeeh Khoury - rabeeh@galileo.co.il + * Based on code done by - Mark A. Greer <mgreer@mvista.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/* Radstone PPC7D boards are rugged VME boards with PPC 7447A CPUs, + * Discovery-II, dual gigabit ethernet, dual PMC, USB, keyboard/mouse, + * 4 serial ports, 2 high speed serial ports (MPSCs) and optional + * SCSI / VGA. + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/major.h> +#include <linux/initrd.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/ide.h> +#include <linux/seq_file.h> +#include <linux/root_dev.h> +#include <linux/serial.h> +#include <linux/tty.h> /* for linux/serial_core.h */ +#include <linux/serial_core.h> +#include <linux/mv643xx.h> +#include <linux/netdevice.h> + +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/time.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/machdep.h> +#include <asm/prom.h> +#include <asm/smp.h> +#include <asm/vga.h> +#include <asm/open_pic.h> +#include <asm/i8259.h> +#include <asm/todc.h> +#include <asm/bootinfo.h> +#include <asm/mpc10x.h> +#include <asm/pci-bridge.h> +#include <asm/mv64x60.h> +#include <asm/i8259.h> + +#include "radstone_ppc7d.h" + +#undef DEBUG + +#define PPC7D_RST_PIN 17 /* GPP17 */ + +extern u32 mv64360_irq_base; + +static struct mv64x60_handle bh; +static int ppc7d_has_alma; + +extern void gen550_progress(char *, unsigned short); +extern void gen550_init(int, struct uart_port *); + +/* residual data */ +unsigned char __res[sizeof(bd_t)]; + +/***************************************************************************** + * Serial port code + *****************************************************************************/ + +#if defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG) +static void __init ppc7d_early_serial_map(void) +{ +#if defined(CONFIG_SERIAL_MPSC_CONSOLE) + mv64x60_progress_init(CONFIG_MV64X60_NEW_BASE); +#elif defined(CONFIG_SERIAL_8250) + struct uart_port serial_req; + + /* Setup serial port access */ + memset(&serial_req, 0, sizeof(serial_req)); + serial_req.uartclk = UART_CLK; + serial_req.irq = 4; + serial_req.flags = STD_COM_FLAGS; + serial_req.iotype = SERIAL_IO_MEM; + serial_req.membase = (u_char *) PPC7D_SERIAL_0; + + gen550_init(0, &serial_req); + if (early_serial_setup(&serial_req) != 0) + printk(KERN_ERR "Early serial init of port 0 failed\n"); + + /* Assume early_serial_setup() doesn't modify serial_req */ + serial_req.line = 1; + serial_req.irq = 3; + serial_req.membase = (u_char *) PPC7D_SERIAL_1; + + gen550_init(1, &serial_req); + if (early_serial_setup(&serial_req) != 0) + printk(KERN_ERR "Early serial init of port 1 failed\n"); +#else +#error CONFIG_KGDB || CONFIG_SERIAL_TEXT_DEBUG has no supported CONFIG_SERIAL_XXX +#endif +} +#endif /* CONFIG_KGDB || CONFIG_SERIAL_TEXT_DEBUG */ + +/***************************************************************************** + * Low-level board support code + *****************************************************************************/ + +static unsigned long __init ppc7d_find_end_of_memory(void) +{ + bd_t *bp = (bd_t *) __res; + + if (bp->bi_memsize) + return bp->bi_memsize; + + return (256 * 1024 * 1024); +} + +static void __init ppc7d_map_io(void) +{ + /* remove temporary mapping */ + mtspr(SPRN_DBAT3U, 0x00000000); + mtspr(SPRN_DBAT3L, 0x00000000); + + io_block_mapping(0xe8000000, 0xe8000000, 0x08000000, _PAGE_IO); + io_block_mapping(0xfe000000, 0xfe000000, 0x02000000, _PAGE_IO); +} + +static void ppc7d_restart(char *cmd) +{ + u32 data; + + /* Disable GPP17 interrupt */ + data = mv64x60_read(&bh, MV64x60_GPP_INTR_MASK); + data &= ~(1 << PPC7D_RST_PIN); + mv64x60_write(&bh, MV64x60_GPP_INTR_MASK, data); + + /* Configure MPP17 as GPP */ + data = mv64x60_read(&bh, MV64x60_MPP_CNTL_2); + data &= ~(0x0000000f << 4); + mv64x60_write(&bh, MV64x60_MPP_CNTL_2, data); + + /* Enable pin GPP17 for output */ + data = mv64x60_read(&bh, MV64x60_GPP_IO_CNTL); + data |= (1 << PPC7D_RST_PIN); + mv64x60_write(&bh, MV64x60_GPP_IO_CNTL, data); + + /* Toggle GPP9 pin to reset the board */ + mv64x60_write(&bh, MV64x60_GPP_VALUE_CLR, 1 << PPC7D_RST_PIN); + mv64x60_write(&bh, MV64x60_GPP_VALUE_SET, 1 << PPC7D_RST_PIN); + + for (;;) ; /* Spin until reset happens */ + /* NOTREACHED */ +} + +static void ppc7d_power_off(void) +{ + u32 data; + + local_irq_disable(); + + /* Ensure that internal MV643XX watchdog is disabled. + * The Disco watchdog uses MPP17 on this hardware. + */ + data = mv64x60_read(&bh, MV64x60_MPP_CNTL_2); + data &= ~(0x0000000f << 4); + mv64x60_write(&bh, MV64x60_MPP_CNTL_2, data); + + data = mv64x60_read(&bh, MV64x60_WDT_WDC); + if (data & 0x80000000) { + mv64x60_write(&bh, MV64x60_WDT_WDC, 1 << 24); + mv64x60_write(&bh, MV64x60_WDT_WDC, 2 << 24); + } + + for (;;) ; /* No way to shut power off with software */ + /* NOTREACHED */ +} + +static void ppc7d_halt(void) +{ + ppc7d_power_off(); + /* NOTREACHED */ +} + +static unsigned long ppc7d_led_no_pulse; + +static int __init ppc7d_led_pulse_disable(char *str) +{ + ppc7d_led_no_pulse = 1; + return 1; +} + +/* This kernel option disables the heartbeat pulsing of a board LED */ +__setup("ledoff", ppc7d_led_pulse_disable); + +static void ppc7d_heartbeat(void) +{ + u32 data32; + u8 data8; + static int max706_wdog = 0; + + /* Unfortunately we can't access the LED control registers + * during early init because they're on the CPLD which is the + * other side of a PCI bridge which goes unreachable during + * PCI scan. So write the LEDs only if the MV64360 watchdog is + * enabled (i.e. userspace apps are running so kernel is up).. + */ + data32 = mv64x60_read(&bh, MV64x60_WDT_WDC); + if (data32 & 0x80000000) { + /* Enable MAX706 watchdog if not done already */ + if (!max706_wdog) { + outb(3, PPC7D_CPLD_RESET); + max706_wdog = 1; + } + + /* Hit the MAX706 watchdog */ + outb(0, PPC7D_CPLD_WATCHDOG_TRIG); + + /* Pulse LED DS219 if not disabled */ + if (!ppc7d_led_no_pulse) { + static int led_on = 0; + + data8 = inb(PPC7D_CPLD_LEDS); + if (led_on) + data8 &= ~PPC7D_CPLD_LEDS_DS219_MASK; + else + data8 |= PPC7D_CPLD_LEDS_DS219_MASK; + + outb(data8, PPC7D_CPLD_LEDS); + led_on = !led_on; + } + } + ppc_md.heartbeat_count = ppc_md.heartbeat_reset; +} + +static int ppc7d_show_cpuinfo(struct seq_file *m) +{ + u8 val; + u8 val1, val2; + static int flash_sizes[4] = { 64, 32, 0, 16 }; + static int flash_banks[4] = { 4, 3, 2, 1 }; + static char *pci_modes[] = { "PCI33", "PCI66", + "Unknown", "Unknown", + "PCIX33", "PCIX66", + "PCIX100", "PCIX133" + }; + + seq_printf(m, "vendor\t\t: Radstone Technology\n"); + seq_printf(m, "machine\t\t: PPC7D\n"); + + val = inb(PPC7D_CPLD_BOARD_REVISION); + val1 = (val & PPC7D_CPLD_BOARD_REVISION_NUMBER_MASK) >> 5; + val2 = (val & PPC7D_CPLD_BOARD_REVISION_LETTER_MASK); + seq_printf(m, "revision\t: %hd%c%c\n", + val1, + (val2 <= 0x18) ? 'A' + val2 : 'Y', + (val2 > 0x18) ? 'A' + (val2 - 0x19) : ' '); + + val = inb(PPC7D_CPLD_MOTHERBOARD_TYPE); + val1 = val & PPC7D_CPLD_MB_TYPE_PLL_MASK; + val2 = val & (PPC7D_CPLD_MB_TYPE_ECC_FITTED_MASK | + PPC7D_CPLD_MB_TYPE_ECC_ENABLE_MASK); + seq_printf(m, "bus speed\t: %dMHz\n", + (val1 == PPC7D_CPLD_MB_TYPE_PLL_133) ? 133 : + (val1 == PPC7D_CPLD_MB_TYPE_PLL_100) ? 100 : + (val1 == PPC7D_CPLD_MB_TYPE_PLL_64) ? 64 : 0); + + val = inb(PPC7D_CPLD_MEM_CONFIG_EXTEND); + val1 = val & PPC7D_CPLD_SDRAM_BANK_SIZE_MASK; + seq_printf(m, "SDRAM\t\t: %d%c", + (val1 == PPC7D_CPLD_SDRAM_BANK_SIZE_128M) ? 128 : + (val1 == PPC7D_CPLD_SDRAM_BANK_SIZE_256M) ? 256 : + (val1 == PPC7D_CPLD_SDRAM_BANK_SIZE_512M) ? 512 : 1, + (val1 == PPC7D_CPLD_SDRAM_BANK_SIZE_1G) ? 'G' : 'M'); + if (val2 & PPC7D_CPLD_MB_TYPE_ECC_FITTED_MASK) { + seq_printf(m, " [ECC %sabled]", + (val2 & PPC7D_CPLD_MB_TYPE_ECC_ENABLE_MASK) ? "en" : + "dis"); + } + seq_printf(m, "\n"); + + val1 = (val & PPC7D_CPLD_FLASH_DEV_SIZE_MASK); + val2 = (val & PPC7D_CPLD_FLASH_BANK_NUM_MASK) >> 2; + seq_printf(m, "FLASH\t\t: %d banks of %dM, total %dM\n", + flash_banks[val2], flash_sizes[val1], + flash_banks[val2] * flash_sizes[val1]); + + val = inb(PPC7D_CPLD_FLASH_WRITE_CNTL); + val1 = inb(PPC7D_CPLD_SW_FLASH_WRITE_PROTECT); + seq_printf(m, " write links\t: %s%s%s%s\n", + (val & PPD7D_CPLD_FLASH_CNTL_WR_LINK_MASK) ? "WRITE " : "", + (val & PPD7D_CPLD_FLASH_CNTL_BOOT_LINK_MASK) ? "BOOT " : "", + (val & PPD7D_CPLD_FLASH_CNTL_USER_LINK_MASK) ? "USER " : "", + (val & (PPD7D_CPLD_FLASH_CNTL_WR_LINK_MASK | + PPD7D_CPLD_FLASH_CNTL_BOOT_LINK_MASK | + PPD7D_CPLD_FLASH_CNTL_USER_LINK_MASK)) == + 0 ? "NONE" : ""); + seq_printf(m, " write sector h/w enables: %s%s%s%s%s\n", + (val & PPD7D_CPLD_FLASH_CNTL_RECO_WR_MASK) ? "RECOVERY " : + "", + (val & PPD7D_CPLD_FLASH_CNTL_BOOT_WR_MASK) ? "BOOT " : "", + (val & PPD7D_CPLD_FLASH_CNTL_USER_WR_MASK) ? "USER " : "", + (val1 & PPC7D_CPLD_FLASH_CNTL_NVRAM_PROT_MASK) ? "NVRAM " : + "", + (((val & + (PPD7D_CPLD_FLASH_CNTL_RECO_WR_MASK | + PPD7D_CPLD_FLASH_CNTL_BOOT_WR_MASK | + PPD7D_CPLD_FLASH_CNTL_BOOT_WR_MASK)) == 0) + && ((val1 & PPC7D_CPLD_FLASH_CNTL_NVRAM_PROT_MASK) == + 0)) ? "NONE" : ""); + val1 = + inb(PPC7D_CPLD_SW_FLASH_WRITE_PROTECT) & + (PPC7D_CPLD_SW_FLASH_WRPROT_SYSBOOT_MASK | + PPC7D_CPLD_SW_FLASH_WRPROT_USER_MASK); + seq_printf(m, " software sector enables: %s%s%s\n", + (val1 & PPC7D_CPLD_SW_FLASH_WRPROT_SYSBOOT_MASK) ? "SYSBOOT " + : "", + (val1 & PPC7D_CPLD_SW_FLASH_WRPROT_USER_MASK) ? "USER " : "", + (val1 == 0) ? "NONE " : ""); + + seq_printf(m, "Boot options\t: %s%s%s%s\n", + (val & PPC7D_CPLD_FLASH_CNTL_ALTBOOT_LINK_MASK) ? + "ALTERNATE " : "", + (val & PPC7D_CPLD_FLASH_CNTL_VMEBOOT_LINK_MASK) ? "VME " : + "", + (val & PPC7D_CPLD_FLASH_CNTL_RECBOOT_LINK_MASK) ? "RECOVERY " + : "", + ((val & + (PPC7D_CPLD_FLASH_CNTL_ALTBOOT_LINK_MASK | + PPC7D_CPLD_FLASH_CNTL_VMEBOOT_LINK_MASK | + PPC7D_CPLD_FLASH_CNTL_RECBOOT_LINK_MASK)) == + 0) ? "NONE" : ""); + + val = inb(PPC7D_CPLD_EQUIPMENT_PRESENT_1); + seq_printf(m, "Fitted modules\t: %s%s%s%s\n", + (val & PPC7D_CPLD_EQPT_PRES_1_PMC1_MASK) ? "" : "PMC1 ", + (val & PPC7D_CPLD_EQPT_PRES_1_PMC2_MASK) ? "" : "PMC2 ", + (val & PPC7D_CPLD_EQPT_PRES_1_AFIX_MASK) ? "AFIX " : "", + ((val & (PPC7D_CPLD_EQPT_PRES_1_PMC1_MASK | + PPC7D_CPLD_EQPT_PRES_1_PMC2_MASK | + PPC7D_CPLD_EQPT_PRES_1_AFIX_MASK)) == + (PPC7D_CPLD_EQPT_PRES_1_PMC1_MASK | + PPC7D_CPLD_EQPT_PRES_1_PMC2_MASK)) ? "NONE" : ""); + + if (val & PPC7D_CPLD_EQPT_PRES_1_AFIX_MASK) { + static const char *ids[] = { + "unknown", + "1553 (Dual Channel)", + "1553 (Single Channel)", + "8-bit SCSI + VGA", + "16-bit SCSI + VGA", + "1553 (Single Channel with sideband)", + "1553 (Dual Channel with sideband)", + NULL + }; + u8 id = __raw_readb((void *)PPC7D_AFIX_REG_BASE + 0x03); + seq_printf(m, "AFIX module\t: 0x%hx [%s]\n", id, + id < 7 ? ids[id] : "unknown"); + } + + val = inb(PPC7D_CPLD_PCI_CONFIG); + val1 = (val & PPC7D_CPLD_PCI_CONFIG_PCI0_MASK) >> 4; + val2 = (val & PPC7D_CPLD_PCI_CONFIG_PCI1_MASK); + seq_printf(m, "PCI#0\t\t: %s\nPCI#1\t\t: %s\n", + pci_modes[val1], pci_modes[val2]); + + val = inb(PPC7D_CPLD_EQUIPMENT_PRESENT_2); + seq_printf(m, "PMC1\t\t: %s\nPMC2\t\t: %s\n", + (val & PPC7D_CPLD_EQPT_PRES_3_PMC1_V_MASK) ? "3.3v" : "5v", + (val & PPC7D_CPLD_EQPT_PRES_3_PMC2_V_MASK) ? "3.3v" : "5v"); + seq_printf(m, "PMC power source: %s\n", + (val & PPC7D_CPLD_EQPT_PRES_3_PMC_POWER_MASK) ? "VME" : + "internal"); + + val = inb(PPC7D_CPLD_EQUIPMENT_PRESENT_4); + val2 = inb(PPC7D_CPLD_EQUIPMENT_PRESENT_2); + seq_printf(m, "Fit options\t: %s%s%s%s%s%s%s\n", + (val & PPC7D_CPLD_EQPT_PRES_4_LPT_MASK) ? "LPT " : "", + (val & PPC7D_CPLD_EQPT_PRES_4_PS2_FITTED) ? "PS2 " : "", + (val & PPC7D_CPLD_EQPT_PRES_4_USB2_FITTED) ? "USB2 " : "", + (val2 & PPC7D_CPLD_EQPT_PRES_2_UNIVERSE_MASK) ? "VME " : "", + (val2 & PPC7D_CPLD_EQPT_PRES_2_COM36_MASK) ? "COM3-6 " : "", + (val2 & PPC7D_CPLD_EQPT_PRES_2_GIGE_MASK) ? "eth0 " : "", + (val2 & PPC7D_CPLD_EQPT_PRES_2_DUALGIGE_MASK) ? "eth1 " : + ""); + + val = inb(PPC7D_CPLD_ID_LINK); + val1 = val & (PPC7D_CPLD_ID_LINK_E6_MASK | + PPC7D_CPLD_ID_LINK_E7_MASK | + PPC7D_CPLD_ID_LINK_E12_MASK | + PPC7D_CPLD_ID_LINK_E13_MASK); + + val = inb(PPC7D_CPLD_FLASH_WRITE_CNTL) & + (PPD7D_CPLD_FLASH_CNTL_WR_LINK_MASK | + PPD7D_CPLD_FLASH_CNTL_BOOT_LINK_MASK | + PPD7D_CPLD_FLASH_CNTL_USER_LINK_MASK); + + seq_printf(m, "Board links present: %s%s%s%s%s%s%s%s\n", + (val1 & PPC7D_CPLD_ID_LINK_E6_MASK) ? "E6 " : "", + (val1 & PPC7D_CPLD_ID_LINK_E7_MASK) ? "E7 " : "", + (val & PPD7D_CPLD_FLASH_CNTL_WR_LINK_MASK) ? "E9 " : "", + (val & PPD7D_CPLD_FLASH_CNTL_BOOT_LINK_MASK) ? "E10 " : "", + (val & PPD7D_CPLD_FLASH_CNTL_USER_LINK_MASK) ? "E11 " : "", + (val1 & PPC7D_CPLD_ID_LINK_E12_MASK) ? "E12 " : "", + (val1 & PPC7D_CPLD_ID_LINK_E13_MASK) ? "E13 " : "", + ((val == 0) && (val1 == 0)) ? "NONE" : ""); + + val = inb(PPC7D_CPLD_WDOG_RESETSW_MASK); + seq_printf(m, "Front panel reset switch: %sabled\n", + (val & PPC7D_CPLD_WDOG_RESETSW_MASK) ? "dis" : "en"); + + return 0; +} + +static void __init ppc7d_calibrate_decr(void) +{ + ulong freq; + + freq = 100000000 / 4; + + pr_debug("time_init: decrementer frequency = %lu.%.6lu MHz\n", + freq / 1000000, freq % 1000000); + + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); +} + +/***************************************************************************** + * Interrupt stuff + *****************************************************************************/ + +static irqreturn_t ppc7d_i8259_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + u32 temp = mv64x60_read(&bh, MV64x60_GPP_INTR_CAUSE); + if (temp & (1 << 28)) { + i8259_irq(regs); + mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, temp & (~(1 << 28))); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +/* + * Each interrupt cause is assigned an IRQ number. + * Southbridge has 16*2 (two 8259's) interrupts. + * Discovery-II has 96 interrupts (cause-hi, cause-lo, gpp x 32). + * If multiple interrupts are pending, get_irq() returns the + * lowest pending irq number first. + * + * + * IRQ # Source Trig Active + * ============================================================= + * + * Southbridge + * ----------- + * IRQ # Source Trig + * ============================================================= + * 0 ISA High Resolution Counter Edge + * 1 Keyboard Edge + * 2 Cascade From (IRQ 8-15) Edge + * 3 Com 2 (Uart 2) Edge + * 4 Com 1 (Uart 1) Edge + * 5 PCI Int D/AFIX IRQZ ID4 (2,7) Level + * 6 GPIO Level + * 7 LPT Edge + * 8 RTC Alarm Edge + * 9 PCI Int A/PMC 2/AFIX IRQW ID1 (2,0) Level + * 10 PCI Int B/PMC 1/AFIX IRQX ID2 (2,1) Level + * 11 USB2 Level + * 12 Mouse Edge + * 13 Reserved internally by Ali M1535+ + * 14 PCI Int C/VME/AFIX IRQY ID3 (2,6) Level + * 15 COM 5/6 Level + * + * 16..112 Discovery-II... + * + * MPP28 Southbridge Edge High + * + * + * Interrupts are cascaded through to the Discovery-II. + * + * PCI --- + * \ + * CPLD --> ALI1535 -------> DISCOVERY-II + * INTF MPP28 + */ +static void __init ppc7d_init_irq(void) +{ + int irq; + + pr_debug("%s\n", __FUNCTION__); + i8259_init(0); + mv64360_init_irq(); + + /* IRQ 0..15 are handled by the cascaded 8259's of the Ali1535 */ + for (irq = 0; irq < 16; irq++) { + irq_desc[irq].handler = &i8259_pic; + } + /* IRQs 5,6,9,10,11,14,15 are level sensitive */ + irq_desc[5].status |= IRQ_LEVEL; + irq_desc[6].status |= IRQ_LEVEL; + irq_desc[9].status |= IRQ_LEVEL; + irq_desc[10].status |= IRQ_LEVEL; + irq_desc[11].status |= IRQ_LEVEL; + irq_desc[14].status |= IRQ_LEVEL; + irq_desc[15].status |= IRQ_LEVEL; + + /* GPP28 is edge triggered */ + irq_desc[mv64360_irq_base + MV64x60_IRQ_GPP28].status &= ~IRQ_LEVEL; +} + +static u32 ppc7d_irq_canonicalize(u32 irq) +{ + if ((irq >= 16) && (irq < (16 + 96))) + irq -= 16; + + return irq; +} + +static int ppc7d_get_irq(struct pt_regs *regs) +{ + int irq; + + irq = mv64360_get_irq(regs); + if (irq == (mv64360_irq_base + MV64x60_IRQ_GPP28)) + irq = i8259_irq(regs); + return irq; +} + +/* + * 9 PCI Int A/PMC 2/AFIX IRQW ID1 (2,0) Level + * 10 PCI Int B/PMC 1/AFIX IRQX ID2 (2,1) Level + * 14 PCI Int C/VME/AFIX IRQY ID3 (2,6) Level + * 5 PCI Int D/AFIX IRQZ ID4 (2,7) Level + */ +static int __init ppc7d_map_irq(struct pci_dev *dev, unsigned char idsel, + unsigned char pin) +{ + static const char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {10, 14, 5, 9}, /* IDSEL 10 - PMC2 / AFIX IRQW */ + {9, 10, 14, 5}, /* IDSEL 11 - PMC1 / AFIX IRQX */ + {5, 9, 10, 14}, /* IDSEL 12 - AFIX IRQY */ + {14, 5, 9, 10}, /* IDSEL 13 - AFIX IRQZ */ + }; + const long min_idsel = 10, max_idsel = 14, irqs_per_slot = 4; + + pr_debug("%s: %04x/%04x/%x: idsel=%hx pin=%hu\n", __FUNCTION__, + dev->vendor, dev->device, PCI_FUNC(dev->devfn), idsel, pin); + + return PCI_IRQ_TABLE_LOOKUP; +} + +void __init ppc7d_intr_setup(void) +{ + u32 data; + + /* + * Define GPP 28 interrupt polarity as active high + * input signal and level triggered + */ + data = mv64x60_read(&bh, MV64x60_GPP_LEVEL_CNTL); + data &= ~(1 << 28); + mv64x60_write(&bh, MV64x60_GPP_LEVEL_CNTL, data); + data = mv64x60_read(&bh, MV64x60_GPP_IO_CNTL); + data &= ~(1 << 28); + mv64x60_write(&bh, MV64x60_GPP_IO_CNTL, data); + + /* Config GPP intr ctlr to respond to level trigger */ + data = mv64x60_read(&bh, MV64x60_COMM_ARBITER_CNTL); + data |= (1 << 10); + mv64x60_write(&bh, MV64x60_COMM_ARBITER_CNTL, data); + + /* XXXX Erranum FEr PCI-#8 */ + data = mv64x60_read(&bh, MV64x60_PCI0_CMD); + data &= ~((1 << 5) | (1 << 9)); + mv64x60_write(&bh, MV64x60_PCI0_CMD, data); + data = mv64x60_read(&bh, MV64x60_PCI1_CMD); + data &= ~((1 << 5) | (1 << 9)); + mv64x60_write(&bh, MV64x60_PCI1_CMD, data); + + /* + * Dismiss and then enable interrupt on GPP interrupt cause + * for CPU #0 + */ + mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, ~(1 << 28)); + data = mv64x60_read(&bh, MV64x60_GPP_INTR_MASK); + data |= (1 << 28); + mv64x60_write(&bh, MV64x60_GPP_INTR_MASK, data); + + /* + * Dismiss and then enable interrupt on CPU #0 high cause reg + * BIT27 summarizes GPP interrupts 23-31 + */ + mv64x60_write(&bh, MV64360_IC_MAIN_CAUSE_HI, ~(1 << 27)); + data = mv64x60_read(&bh, MV64360_IC_CPU0_INTR_MASK_HI); + data |= (1 << 27); + mv64x60_write(&bh, MV64360_IC_CPU0_INTR_MASK_HI, data); +} + +/***************************************************************************** + * Platform device data fixup routines. + *****************************************************************************/ + +#if defined(CONFIG_SERIAL_MPSC) +static void __init ppc7d_fixup_mpsc_pdata(struct platform_device *pdev) +{ + struct mpsc_pdata *pdata; + + pdata = (struct mpsc_pdata *)pdev->dev.platform_data; + + pdata->max_idle = 40; + pdata->default_baud = PPC7D_DEFAULT_BAUD; + pdata->brg_clk_src = PPC7D_MPSC_CLK_SRC; + pdata->brg_clk_freq = PPC7D_MPSC_CLK_FREQ; + + return; +} +#endif + +#if defined(CONFIG_MV643XX_ETH) +static void __init ppc7d_fixup_eth_pdata(struct platform_device *pdev) +{ + struct mv643xx_eth_platform_data *eth_pd; + static u16 phy_addr[] = { + PPC7D_ETH0_PHY_ADDR, + PPC7D_ETH1_PHY_ADDR, + PPC7D_ETH2_PHY_ADDR, + }; + int i; + + eth_pd = pdev->dev.platform_data; + eth_pd->force_phy_addr = 1; + eth_pd->phy_addr = phy_addr[pdev->id]; + eth_pd->tx_queue_size = PPC7D_ETH_TX_QUEUE_SIZE; + eth_pd->rx_queue_size = PPC7D_ETH_RX_QUEUE_SIZE; + + /* Adjust IRQ by mv64360_irq_base */ + for (i = 0; i < pdev->num_resources; i++) { + struct resource *r = &pdev->resource[i]; + + if (r->flags & IORESOURCE_IRQ) { + r->start += mv64360_irq_base; + r->end += mv64360_irq_base; + pr_debug("%s, uses IRQ %d\n", pdev->name, + (int)r->start); + } + } + +} +#endif + +#if defined(CONFIG_I2C_MV64XXX) +static void __init +ppc7d_fixup_i2c_pdata(struct platform_device *pdev) +{ + struct mv64xxx_i2c_pdata *pdata; + int i; + + pdata = pdev->dev.platform_data; + if (pdata == NULL) { + pdata = kmalloc(sizeof(*pdata), GFP_KERNEL); + if (pdata == NULL) + return; + + memset(pdata, 0, sizeof(*pdata)); + pdev->dev.platform_data = pdata; + } + + /* divisors M=8, N=3 for 100kHz I2C from 133MHz system clock */ + pdata->freq_m = 8; + pdata->freq_n = 3; + pdata->timeout = 500; + pdata->retries = 3; + + /* Adjust IRQ by mv64360_irq_base */ + for (i = 0; i < pdev->num_resources; i++) { + struct resource *r = &pdev->resource[i]; + + if (r->flags & IORESOURCE_IRQ) { + r->start += mv64360_irq_base; + r->end += mv64360_irq_base; + pr_debug("%s, uses IRQ %d\n", pdev->name, (int) r->start); + } + } +} +#endif + +static int __init ppc7d_platform_notify(struct device *dev) +{ + static struct { + char *bus_id; + void ((*rtn) (struct platform_device * pdev)); + } dev_map[] = { +#if defined(CONFIG_SERIAL_MPSC) + { MPSC_CTLR_NAME ".0", ppc7d_fixup_mpsc_pdata }, + { MPSC_CTLR_NAME ".1", ppc7d_fixup_mpsc_pdata }, +#endif +#if defined(CONFIG_MV643XX_ETH) + { MV643XX_ETH_NAME ".0", ppc7d_fixup_eth_pdata }, + { MV643XX_ETH_NAME ".1", ppc7d_fixup_eth_pdata }, + { MV643XX_ETH_NAME ".2", ppc7d_fixup_eth_pdata }, +#endif +#if defined(CONFIG_I2C_MV64XXX) + { MV64XXX_I2C_CTLR_NAME ".0", ppc7d_fixup_i2c_pdata }, +#endif + }; + struct platform_device *pdev; + int i; + + if (dev && dev->bus_id) + for (i = 0; i < ARRAY_SIZE(dev_map); i++) + if (!strncmp(dev->bus_id, dev_map[i].bus_id, + BUS_ID_SIZE)) { + + pdev = container_of(dev, + struct platform_device, + dev); + dev_map[i].rtn(pdev); + } + + return 0; +} + +/***************************************************************************** + * PCI device fixups. + * These aren't really fixups per se. They are used to init devices as they + * are found during PCI scan. + * + * The PPC7D has an HB8 PCI-X bridge which must be set up during a PCI + * scan in order to find other devices on its secondary side. + *****************************************************************************/ + +static void __init ppc7d_fixup_hb8(struct pci_dev *dev) +{ + u16 val16; + + if (dev->bus->number == 0) { + pr_debug("PCI: HB8 init\n"); + + pci_write_config_byte(dev, 0x1c, + ((PPC7D_PCI0_IO_START_PCI_ADDR & 0xf000) + >> 8) | 0x01); + pci_write_config_byte(dev, 0x1d, + (((PPC7D_PCI0_IO_START_PCI_ADDR + + PPC7D_PCI0_IO_SIZE - + 1) & 0xf000) >> 8) | 0x01); + pci_write_config_word(dev, 0x30, + PPC7D_PCI0_IO_START_PCI_ADDR >> 16); + pci_write_config_word(dev, 0x32, + ((PPC7D_PCI0_IO_START_PCI_ADDR + + PPC7D_PCI0_IO_SIZE - + 1) >> 16) & 0xffff); + + pci_write_config_word(dev, 0x20, + PPC7D_PCI0_MEM0_START_PCI_LO_ADDR >> 16); + pci_write_config_word(dev, 0x22, + ((PPC7D_PCI0_MEM0_START_PCI_LO_ADDR + + PPC7D_PCI0_MEM0_SIZE - + 1) >> 16) & 0xffff); + pci_write_config_word(dev, 0x24, 0); + pci_write_config_word(dev, 0x26, 0); + pci_write_config_dword(dev, 0x28, 0); + pci_write_config_dword(dev, 0x2c, 0); + + pci_read_config_word(dev, 0x3e, &val16); + val16 |= ((1 << 5) | (1 << 1)); /* signal master aborts and + * SERR to primary + */ + val16 &= ~(1 << 2); /* ISA disable, so all ISA + * ports forwarded to secondary + */ + pci_write_config_word(dev, 0x3e, val16); + } +} + +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_HINT, 0x0028, ppc7d_fixup_hb8); + +/* This should perhaps be a separate driver as we're actually initializing + * the chip for this board here. It's hardly a fixup... + */ +static void __init ppc7d_fixup_ali1535(struct pci_dev *dev) +{ + pr_debug("PCI: ALI1535 init\n"); + + if (dev->bus->number == 1) { + /* Configure the ISA Port Settings */ + pci_write_config_byte(dev, 0x43, 0x00); + + /* Disable PCI Interrupt polling mode */ + pci_write_config_byte(dev, 0x45, 0x00); + + /* Multifunction pin select INTFJ -> INTF */ + pci_write_config_byte(dev, 0x78, 0x00); + + /* Set PCI INT -> IRQ Routing control in for external + * pins south bridge. + */ + pci_write_config_byte(dev, 0x48, 0x31); /* [7-4] INT B -> IRQ10 + * [3-0] INT A -> IRQ9 + */ + pci_write_config_byte(dev, 0x49, 0x5D); /* [7-4] INT D -> IRQ5 + * [3-0] INT C -> IRQ14 + */ + + /* PPC7D setup */ + /* NEC USB device on IRQ 11 (INTE) - INTF disabled */ + pci_write_config_byte(dev, 0x4A, 0x09); + + /* GPIO on IRQ 6 */ + pci_write_config_byte(dev, 0x76, 0x07); + + /* SIRQ I (COMS 5/6) use IRQ line 15. + * Positive (not subtractive) address decode. + */ + pci_write_config_byte(dev, 0x44, 0x0f); + + /* SIRQ II disabled */ + pci_write_config_byte(dev, 0x75, 0x0); + + /* On board USB and RTC disabled */ + pci_write_config_word(dev, 0x52, (1 << 14)); + pci_write_config_byte(dev, 0x74, 0x00); + + /* On board IDE disabled */ + pci_write_config_byte(dev, 0x58, 0x00); + + /* Decode 32-bit addresses */ + pci_write_config_byte(dev, 0x5b, 0); + + /* Disable docking IO */ + pci_write_config_word(dev, 0x5c, 0x0000); + + /* Disable modem, enable sound */ + pci_write_config_byte(dev, 0x77, (1 << 6)); + + /* Disable hot-docking mode */ + pci_write_config_byte(dev, 0x7d, 0x00); + } +} + +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x1533, ppc7d_fixup_ali1535); + +static int ppc7d_pci_exclude_device(u8 bus, u8 devfn) +{ + /* Early versions of this board were fitted with IBM ALMA + * PCI-VME bridge chips. The PCI config space of these devices + * was not set up correctly and causes PCI scan problems. + */ + if ((bus == 1) && (PCI_SLOT(devfn) == 4) && ppc7d_has_alma) + return PCIBIOS_DEVICE_NOT_FOUND; + + return mv64x60_pci_exclude_device(bus, devfn); +} + +/* This hook is called when each PCI bus is probed. + */ +static void ppc7d_pci_fixup_bus(struct pci_bus *bus) +{ + pr_debug("PCI BUS %hu: %lx/%lx %lx/%lx %lx/%lx %lx/%lx\n", + bus->number, + bus->resource[0] ? bus->resource[0]->start : 0, + bus->resource[0] ? bus->resource[0]->end : 0, + bus->resource[1] ? bus->resource[1]->start : 0, + bus->resource[1] ? bus->resource[1]->end : 0, + bus->resource[2] ? bus->resource[2]->start : 0, + bus->resource[2] ? bus->resource[2]->end : 0, + bus->resource[3] ? bus->resource[3]->start : 0, + bus->resource[3] ? bus->resource[3]->end : 0); + + if ((bus->number == 1) && (bus->resource[2] != NULL)) { + /* Hide PCI window 2 of Bus 1 which is used only to + * map legacy ISA memory space. + */ + bus->resource[2]->start = 0; + bus->resource[2]->end = 0; + bus->resource[2]->flags = 0; + } +} + +/***************************************************************************** + * Board device setup code + *****************************************************************************/ + +void __init ppc7d_setup_peripherals(void) +{ + u32 val32; + + /* Set up windows for boot CS */ + mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN, + PPC7D_BOOT_WINDOW_BASE, PPC7D_BOOT_WINDOW_SIZE, + 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN); + + /* Boot firmware configures the following DevCS addresses. + * DevCS0 - board control/status + * DevCS1 - test registers + * DevCS2 - AFIX port/address registers (for identifying) + * DevCS3 - FLASH + * + * We don't use DevCS0, DevCS1. + */ + val32 = mv64x60_read(&bh, MV64360_CPU_BAR_ENABLE); + val32 |= ((1 << 4) | (1 << 5)); + mv64x60_write(&bh, MV64360_CPU_BAR_ENABLE, val32); + mv64x60_write(&bh, MV64x60_CPU2DEV_0_BASE, 0); + mv64x60_write(&bh, MV64x60_CPU2DEV_0_SIZE, 0); + mv64x60_write(&bh, MV64x60_CPU2DEV_1_BASE, 0); + mv64x60_write(&bh, MV64x60_CPU2DEV_1_SIZE, 0); + + mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_2_WIN, + PPC7D_AFIX_REG_BASE, PPC7D_AFIX_REG_SIZE, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_2_WIN); + + mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_3_WIN, + PPC7D_FLASH_BASE, PPC7D_FLASH_SIZE_ACTUAL, 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_3_WIN); + + mv64x60_set_32bit_window(&bh, MV64x60_CPU2SRAM_WIN, + PPC7D_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE, + 0); + bh.ci->enable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN); + + /* Set up Enet->SRAM window */ + mv64x60_set_32bit_window(&bh, MV64x60_ENET2MEM_4_WIN, + PPC7D_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE, + 0x2); + bh.ci->enable_window_32bit(&bh, MV64x60_ENET2MEM_4_WIN); + + /* Give enet r/w access to memory region */ + val32 = mv64x60_read(&bh, MV64360_ENET2MEM_ACC_PROT_0); + val32 |= (0x3 << (4 << 1)); + mv64x60_write(&bh, MV64360_ENET2MEM_ACC_PROT_0, val32); + val32 = mv64x60_read(&bh, MV64360_ENET2MEM_ACC_PROT_1); + val32 |= (0x3 << (4 << 1)); + mv64x60_write(&bh, MV64360_ENET2MEM_ACC_PROT_1, val32); + val32 = mv64x60_read(&bh, MV64360_ENET2MEM_ACC_PROT_2); + val32 |= (0x3 << (4 << 1)); + mv64x60_write(&bh, MV64360_ENET2MEM_ACC_PROT_2, val32); + + val32 = mv64x60_read(&bh, MV64x60_TIMR_CNTR_0_3_CNTL); + val32 &= ~((1 << 0) | (1 << 8) | (1 << 16) | (1 << 24)); + mv64x60_write(&bh, MV64x60_TIMR_CNTR_0_3_CNTL, val32); + + /* Enumerate pci bus. + * + * We scan PCI#0 first (the bus with the HB8 and other + * on-board peripherals). We must configure the 64360 before + * each scan, according to the bus number assignments. Busses + * are assigned incrementally, starting at 0. PCI#0 is + * usually assigned bus#0, the secondary side of the HB8 gets + * bus#1 and PCI#1 (second PMC site) gets bus#2. However, if + * any PMC card has a PCI bridge, these bus assignments will + * change. + */ + + /* Turn off PCI retries */ + val32 = mv64x60_read(&bh, MV64x60_CPU_CONFIG); + val32 |= (1 << 17); + mv64x60_write(&bh, MV64x60_CPU_CONFIG, val32); + + /* Scan PCI#0 */ + mv64x60_set_bus(&bh, 0, 0); + bh.hose_a->first_busno = 0; + bh.hose_a->last_busno = 0xff; + bh.hose_a->last_busno = pciauto_bus_scan(bh.hose_a, 0); + printk(KERN_INFO "PCI#0: first=%d last=%d\n", + bh.hose_a->first_busno, bh.hose_a->last_busno); + + /* Scan PCI#1 */ + bh.hose_b->first_busno = bh.hose_a->last_busno + 1; + mv64x60_set_bus(&bh, 1, bh.hose_b->first_busno); + bh.hose_b->last_busno = 0xff; + bh.hose_b->last_busno = pciauto_bus_scan(bh.hose_b, + bh.hose_b->first_busno); + printk(KERN_INFO "PCI#1: first=%d last=%d\n", + bh.hose_b->first_busno, bh.hose_b->last_busno); + + /* Turn on PCI retries */ + val32 = mv64x60_read(&bh, MV64x60_CPU_CONFIG); + val32 &= ~(1 << 17); + mv64x60_write(&bh, MV64x60_CPU_CONFIG, val32); + + /* Setup interrupts */ + ppc7d_intr_setup(); +} + +static void __init ppc7d_setup_bridge(void) +{ + struct mv64x60_setup_info si; + int i; + u32 temp; + + mv64360_irq_base = 16; /* first 16 intrs are 2 x 8259's */ + + memset(&si, 0, sizeof(si)); + + si.phys_reg_base = CONFIG_MV64X60_NEW_BASE; + + si.pci_0.enable_bus = 1; + si.pci_0.pci_io.cpu_base = PPC7D_PCI0_IO_START_PROC_ADDR; + si.pci_0.pci_io.pci_base_hi = 0; + si.pci_0.pci_io.pci_base_lo = PPC7D_PCI0_IO_START_PCI_ADDR; + si.pci_0.pci_io.size = PPC7D_PCI0_IO_SIZE; + si.pci_0.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE; + si.pci_0.pci_mem[0].cpu_base = PPC7D_PCI0_MEM0_START_PROC_ADDR; + si.pci_0.pci_mem[0].pci_base_hi = PPC7D_PCI0_MEM0_START_PCI_HI_ADDR; + si.pci_0.pci_mem[0].pci_base_lo = PPC7D_PCI0_MEM0_START_PCI_LO_ADDR; + si.pci_0.pci_mem[0].size = PPC7D_PCI0_MEM0_SIZE; + si.pci_0.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE; + si.pci_0.pci_mem[1].cpu_base = PPC7D_PCI0_MEM1_START_PROC_ADDR; + si.pci_0.pci_mem[1].pci_base_hi = PPC7D_PCI0_MEM1_START_PCI_HI_ADDR; + si.pci_0.pci_mem[1].pci_base_lo = PPC7D_PCI0_MEM1_START_PCI_LO_ADDR; + si.pci_0.pci_mem[1].size = PPC7D_PCI0_MEM1_SIZE; + si.pci_0.pci_mem[1].swap = MV64x60_CPU2PCI_SWAP_NONE; + si.pci_0.pci_cmd_bits = 0; + si.pci_0.latency_timer = 0x80; + + si.pci_1.enable_bus = 1; + si.pci_1.pci_io.cpu_base = PPC7D_PCI1_IO_START_PROC_ADDR; + si.pci_1.pci_io.pci_base_hi = 0; + si.pci_1.pci_io.pci_base_lo = PPC7D_PCI1_IO_START_PCI_ADDR; + si.pci_1.pci_io.size = PPC7D_PCI1_IO_SIZE; + si.pci_1.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE; + si.pci_1.pci_mem[0].cpu_base = PPC7D_PCI1_MEM0_START_PROC_ADDR; + si.pci_1.pci_mem[0].pci_base_hi = PPC7D_PCI1_MEM0_START_PCI_HI_ADDR; + si.pci_1.pci_mem[0].pci_base_lo = PPC7D_PCI1_MEM0_START_PCI_LO_ADDR; + si.pci_1.pci_mem[0].size = PPC7D_PCI1_MEM0_SIZE; + si.pci_1.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE; + si.pci_1.pci_mem[1].cpu_base = PPC7D_PCI1_MEM1_START_PROC_ADDR; + si.pci_1.pci_mem[1].pci_base_hi = PPC7D_PCI1_MEM1_START_PCI_HI_ADDR; + si.pci_1.pci_mem[1].pci_base_lo = PPC7D_PCI1_MEM1_START_PCI_LO_ADDR; + si.pci_1.pci_mem[1].size = PPC7D_PCI1_MEM1_SIZE; + si.pci_1.pci_mem[1].swap = MV64x60_CPU2PCI_SWAP_NONE; + si.pci_1.pci_cmd_bits = 0; + si.pci_1.latency_timer = 0x80; + + /* Don't clear the SRAM window since we use it for debug */ + si.window_preserve_mask_32_lo = (1 << MV64x60_CPU2SRAM_WIN); + + printk(KERN_INFO "PCI: MV64360 PCI#0 IO at %x, size %x\n", + si.pci_0.pci_io.cpu_base, si.pci_0.pci_io.size); + printk(KERN_INFO "PCI: MV64360 PCI#1 IO at %x, size %x\n", + si.pci_1.pci_io.cpu_base, si.pci_1.pci_io.size); + + for (i = 0; i < MV64x60_CPU2MEM_WINDOWS; i++) { +#if defined(CONFIG_NOT_COHERENT_CACHE) + si.cpu_prot_options[i] = 0; + si.enet_options[i] = MV64360_ENET2MEM_SNOOP_NONE; + si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_NONE; + si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE; + + si.pci_0.acc_cntl_options[i] = + MV64360_PCI_ACC_CNTL_SNOOP_NONE | + MV64360_PCI_ACC_CNTL_SWAP_NONE | + MV64360_PCI_ACC_CNTL_MBURST_128_BYTES | + MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES; + + si.pci_1.acc_cntl_options[i] = + MV64360_PCI_ACC_CNTL_SNOOP_NONE | + MV64360_PCI_ACC_CNTL_SWAP_NONE | + MV64360_PCI_ACC_CNTL_MBURST_128_BYTES | + MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES; +#else + si.cpu_prot_options[i] = 0; + /* All PPC7D hardware uses B0 or newer MV64360 silicon which + * does not have snoop bugs. + */ + si.enet_options[i] = MV64360_ENET2MEM_SNOOP_WB; + si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_WB; + si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_WB; + + si.pci_0.acc_cntl_options[i] = + MV64360_PCI_ACC_CNTL_SNOOP_WB | + MV64360_PCI_ACC_CNTL_SWAP_NONE | + MV64360_PCI_ACC_CNTL_MBURST_32_BYTES | + MV64360_PCI_ACC_CNTL_RDSIZE_32_BYTES; + + si.pci_1.acc_cntl_options[i] = + MV64360_PCI_ACC_CNTL_SNOOP_WB | + MV64360_PCI_ACC_CNTL_SWAP_NONE | + MV64360_PCI_ACC_CNTL_MBURST_32_BYTES | + MV64360_PCI_ACC_CNTL_RDSIZE_32_BYTES; +#endif + } + + /* Lookup PCI host bridges */ + if (mv64x60_init(&bh, &si)) + printk(KERN_ERR "MV64360 initialization failed.\n"); + + pr_debug("MV64360 regs @ %lx/%p\n", bh.p_base, bh.v_base); + + /* Enable WB Cache coherency on SRAM */ + temp = mv64x60_read(&bh, MV64360_SRAM_CONFIG); + pr_debug("SRAM_CONFIG: %x\n", temp); +#if defined(CONFIG_NOT_COHERENT_CACHE) + mv64x60_write(&bh, MV64360_SRAM_CONFIG, temp & ~0x2); +#else + mv64x60_write(&bh, MV64360_SRAM_CONFIG, temp | 0x2); +#endif + /* If system operates with internal bus arbiter (CPU master + * control bit8) clear AACK Delay bit [25] in CPU + * configuration register. + */ + temp = mv64x60_read(&bh, MV64x60_CPU_MASTER_CNTL); + if (temp & (1 << 8)) { + temp = mv64x60_read(&bh, MV64x60_CPU_CONFIG); + mv64x60_write(&bh, MV64x60_CPU_CONFIG, (temp & ~(1 << 25))); + } + + /* Data and address parity is enabled */ + temp = mv64x60_read(&bh, MV64x60_CPU_CONFIG); + mv64x60_write(&bh, MV64x60_CPU_CONFIG, + (temp | (1 << 26) | (1 << 19))); + + pci_dram_offset = 0; /* sys mem at same addr on PCI & cpu bus */ + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = ppc7d_map_irq; + ppc_md.pci_exclude_device = ppc7d_pci_exclude_device; + + mv64x60_set_bus(&bh, 0, 0); + bh.hose_a->first_busno = 0; + bh.hose_a->last_busno = 0xff; + bh.hose_a->mem_space.start = PPC7D_PCI0_MEM0_START_PCI_LO_ADDR; + bh.hose_a->mem_space.end = + PPC7D_PCI0_MEM0_START_PCI_LO_ADDR + PPC7D_PCI0_MEM0_SIZE; + + /* These will be set later, as a result of PCI0 scan */ + bh.hose_b->first_busno = 0; + bh.hose_b->last_busno = 0xff; + bh.hose_b->mem_space.start = PPC7D_PCI1_MEM0_START_PCI_LO_ADDR; + bh.hose_b->mem_space.end = + PPC7D_PCI1_MEM0_START_PCI_LO_ADDR + PPC7D_PCI1_MEM0_SIZE; + + pr_debug("MV64360: PCI#0 IO decode %08x/%08x IO remap %08x\n", + mv64x60_read(&bh, 0x48), mv64x60_read(&bh, 0x50), + mv64x60_read(&bh, 0xf0)); +} + +static void __init ppc7d_setup_arch(void) +{ + int port; + + loops_per_jiffy = 100000000 / HZ; + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_HDA1; +#endif + + if ((cur_cpu_spec[0]->cpu_features & CPU_FTR_SPEC7450) || + (cur_cpu_spec[0]->cpu_features & CPU_FTR_L3CR)) + /* 745x is different. We only want to pass along enable. */ + _set_L2CR(L2CR_L2E); + else if (cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR) + /* All modules have 1MB of L2. We also assume that an + * L2 divisor of 3 will work. + */ + _set_L2CR(L2CR_L2E | L2CR_L2SIZ_1MB | L2CR_L2CLK_DIV3 + | L2CR_L2RAM_PIPE | L2CR_L2OH_1_0 | L2CR_L2DF); + + if (cur_cpu_spec[0]->cpu_features & CPU_FTR_L3CR) + /* No L3 cache */ + _set_L3CR(0); + +#ifdef CONFIG_DUMMY_CONSOLE + conswitchp = &dummy_con; +#endif + + /* Lookup PCI host bridges */ + if (ppc_md.progress) + ppc_md.progress("ppc7d_setup_arch: calling setup_bridge", 0); + + ppc7d_setup_bridge(); + ppc7d_setup_peripherals(); + + /* Disable ethernet. It might have been setup by the bootrom */ + for (port = 0; port < 3; port++) + mv64x60_write(&bh, MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port), + 0x0000ff00); + + /* Clear queue pointers to ensure they are all initialized, + * otherwise since queues 1-7 are unused, they have random + * pointers which look strange in register dumps. Don't bother + * with queue 0 since it will be initialized later. + */ + for (port = 0; port < 3; port++) { + mv64x60_write(&bh, + MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_1(port), + 0x00000000); + mv64x60_write(&bh, + MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_2(port), + 0x00000000); + mv64x60_write(&bh, + MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_3(port), + 0x00000000); + mv64x60_write(&bh, + MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_4(port), + 0x00000000); + mv64x60_write(&bh, + MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_5(port), + 0x00000000); + mv64x60_write(&bh, + MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_6(port), + 0x00000000); + mv64x60_write(&bh, + MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_7(port), + 0x00000000); + } + + printk(KERN_INFO "Radstone Technology PPC7D\n"); + if (ppc_md.progress) + ppc_md.progress("ppc7d_setup_arch: exit", 0); +} + +/* This kernel command line parameter can be used to have the target + * wait for a JTAG debugger to attach. Of course, a JTAG debugger + * with hardware breakpoint support can have the target stop at any + * location during init, but this is a convenience feature that makes + * it easier in the common case of loading the code using the ppcboot + * bootloader.. + */ +static unsigned long ppc7d_wait_debugger; + +static int __init ppc7d_waitdbg(char *str) +{ + ppc7d_wait_debugger = 1; + return 1; +} + +__setup("waitdbg", ppc7d_waitdbg); + +/* Second phase board init, called after other (architecture common) + * low-level services have been initialized. + */ +static void ppc7d_init2(void) +{ + unsigned long flags; + u32 data; + u8 data8; + + pr_debug("%s: enter\n", __FUNCTION__); + + /* Wait for debugger? */ + if (ppc7d_wait_debugger) { + printk("Waiting for debugger...\n"); + + while (readl(&ppc7d_wait_debugger)) ; + } + + /* Hook up i8259 interrupt which is connected to GPP28 */ + request_irq(mv64360_irq_base + MV64x60_IRQ_GPP28, ppc7d_i8259_intr, + SA_INTERRUPT, "I8259 (GPP28) interrupt", (void *)0); + + /* Configure MPP16 as watchdog NMI, MPP17 as watchdog WDE */ + spin_lock_irqsave(&mv64x60_lock, flags); + data = mv64x60_read(&bh, MV64x60_MPP_CNTL_2); + data &= ~(0x0000000f << 0); + data |= (0x00000004 << 0); + data &= ~(0x0000000f << 4); + data |= (0x00000004 << 4); + mv64x60_write(&bh, MV64x60_MPP_CNTL_2, data); + spin_unlock_irqrestore(&mv64x60_lock, flags); + + /* All LEDs off */ + data8 = inb(PPC7D_CPLD_LEDS); + data8 &= ~0x08; + data8 |= 0x07; + outb(data8, PPC7D_CPLD_LEDS); + + pr_debug("%s: exit\n", __FUNCTION__); +} + +/* Called from machine_init(), early, before any of the __init functions + * have run. We must init software-configurable pins before other functions + * such as interrupt controllers are initialised. + */ +void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + u8 val8; + u8 rev_num; + + /* Map 0xe0000000-0xffffffff early because we need access to SRAM + * and the ISA memory space (for serial port) here. This mapping + * is redone properly in ppc7d_map_io() later. + */ + mtspr(SPRN_DBAT3U, 0xe0003fff); + mtspr(SPRN_DBAT3L, 0xe000002a); + + /* + * Zero SRAM. Note that this generates parity errors on + * internal data path in SRAM if it's first time accessing it + * after reset. + * + * We do this ASAP to avoid parity errors when reading + * uninitialized SRAM. + */ + memset((void *)PPC7D_INTERNAL_SRAM_BASE, 0, MV64360_SRAM_SIZE); + + pr_debug("platform_init: r3-r7: %lx %lx %lx %lx %lx\n", + r3, r4, r5, r6, r7); + + parse_bootinfo(find_bootinfo()); + + /* ASSUMPTION: If both r3 (bd_t pointer) and r6 (cmdline pointer) + * are non-zero, then we should use the board info from the bd_t + * structure and the cmdline pointed to by r6 instead of the + * information from birecs, if any. Otherwise, use the information + * from birecs as discovered by the preceeding call to + * parse_bootinfo(). This rule should work with both PPCBoot, which + * uses a bd_t board info structure, and the kernel boot wrapper, + * which uses birecs. + */ + if (r3 && r6) { + bd_t *bp = (bd_t *) __res; + + /* copy board info structure */ + memcpy((void *)__res, (void *)(r3 + KERNELBASE), sizeof(bd_t)); + /* copy command line */ + *(char *)(r7 + KERNELBASE) = 0; + strcpy(cmd_line, (char *)(r6 + KERNELBASE)); + + printk(KERN_INFO "Board info data:-\n"); + printk(KERN_INFO " Internal freq: %lu MHz, bus freq: %lu MHz\n", + bp->bi_intfreq, bp->bi_busfreq); + printk(KERN_INFO " Memory: %lx, size %lx\n", bp->bi_memstart, + bp->bi_memsize); + printk(KERN_INFO " Console baudrate: %lu\n", bp->bi_baudrate); + printk(KERN_INFO " Ethernet address: " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + bp->bi_enetaddr[0], bp->bi_enetaddr[1], + bp->bi_enetaddr[2], bp->bi_enetaddr[3], + bp->bi_enetaddr[4], bp->bi_enetaddr[5]); + } +#ifdef CONFIG_BLK_DEV_INITRD + /* take care of initrd if we have one */ + if (r4) { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + printk(KERN_INFO "INITRD @ %lx/%lx\n", initrd_start, initrd_end); + } +#endif /* CONFIG_BLK_DEV_INITRD */ + + /* Map in board regs, etc. */ + isa_io_base = 0xe8000000; + isa_mem_base = 0xe8000000; + pci_dram_offset = 0x00000000; + ISA_DMA_THRESHOLD = 0x00ffffff; + DMA_MODE_READ = 0x44; + DMA_MODE_WRITE = 0x48; + + ppc_md.setup_arch = ppc7d_setup_arch; + ppc_md.init = ppc7d_init2; + ppc_md.show_cpuinfo = ppc7d_show_cpuinfo; + ppc_md.irq_canonicalize = ppc7d_irq_canonicalize; + ppc_md.init_IRQ = ppc7d_init_irq; + ppc_md.get_irq = ppc7d_get_irq; + + ppc_md.restart = ppc7d_restart; + ppc_md.power_off = ppc7d_power_off; + ppc_md.halt = ppc7d_halt; + + ppc_md.find_end_of_memory = ppc7d_find_end_of_memory; + ppc_md.setup_io_mappings = ppc7d_map_io; + + ppc_md.time_init = NULL; + ppc_md.set_rtc_time = NULL; + ppc_md.get_rtc_time = NULL; + ppc_md.calibrate_decr = ppc7d_calibrate_decr; + ppc_md.nvram_read_val = NULL; + ppc_md.nvram_write_val = NULL; + + ppc_md.heartbeat = ppc7d_heartbeat; + ppc_md.heartbeat_reset = HZ; + ppc_md.heartbeat_count = ppc_md.heartbeat_reset; + + ppc_md.pcibios_fixup_bus = ppc7d_pci_fixup_bus; + +#if defined(CONFIG_SERIAL_MPSC) || defined(CONFIG_MV643XX_ETH) || \ + defined(CONFIG_I2C_MV64XXX) + platform_notify = ppc7d_platform_notify; +#endif + +#ifdef CONFIG_SERIAL_MPSC + /* On PPC7D, we must configure MPSC support via CPLD control + * registers. + */ + outb(PPC7D_CPLD_RTS_COM4_SCLK | + PPC7D_CPLD_RTS_COM56_ENABLED, PPC7D_CPLD_RTS); + outb(PPC7D_CPLD_COMS_COM3_TCLKEN | + PPC7D_CPLD_COMS_COM3_TXEN | + PPC7D_CPLD_COMS_COM4_TCLKEN | + PPC7D_CPLD_COMS_COM4_TXEN, PPC7D_CPLD_COMS); +#endif /* CONFIG_SERIAL_MPSC */ + +#if defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG) + ppc7d_early_serial_map(); +#ifdef CONFIG_SERIAL_TEXT_DEBUG +#if defined(CONFIG_SERIAL_MPSC_CONSOLE) + ppc_md.progress = mv64x60_mpsc_progress; +#elif defined(CONFIG_SERIAL_8250) + ppc_md.progress = gen550_progress; +#else +#error CONFIG_KGDB || CONFIG_SERIAL_TEXT_DEBUG has no supported CONFIG_SERIAL_XXX +#endif /* CONFIG_SERIAL_8250 */ +#endif /* CONFIG_SERIAL_TEXT_DEBUG */ +#endif /* CONFIG_KGDB || CONFIG_SERIAL_TEXT_DEBUG */ + + /* Enable write access to user flash. This is necessary for + * flash probe. + */ + val8 = readb((void *)isa_io_base + PPC7D_CPLD_SW_FLASH_WRITE_PROTECT); + writeb(val8 | (PPC7D_CPLD_SW_FLASH_WRPROT_ENABLED & + PPC7D_CPLD_SW_FLASH_WRPROT_USER_MASK), + (void *)isa_io_base + PPC7D_CPLD_SW_FLASH_WRITE_PROTECT); + + /* Determine if this board has IBM ALMA VME devices */ + val8 = readb((void *)isa_io_base + PPC7D_CPLD_BOARD_REVISION); + rev_num = (val8 & PPC7D_CPLD_BOARD_REVISION_NUMBER_MASK) >> 5; + if (rev_num <= 1) + ppc7d_has_alma = 1; + +#ifdef DEBUG + console_printk[0] = 8; +#endif +} diff --git a/arch/ppc/platforms/radstone_ppc7d.h b/arch/ppc/platforms/radstone_ppc7d.h new file mode 100644 index 00000000000..4546fff2b0c --- /dev/null +++ b/arch/ppc/platforms/radstone_ppc7d.h @@ -0,0 +1,434 @@ +/* + * arch/ppc/platforms/radstone_ppc7d.h + * + * Board definitions for the Radstone PPC7D boards. + * + * Author: James Chapman <jchapman@katalix.com> + * + * Based on code done by Rabeeh Khoury - rabeeh@galileo.co.il + * Based on code done by - Mark A. Greer <mgreer@mvista.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/* + * The MV64360 has 2 PCI buses each with 1 window from the CPU bus to + * PCI I/O space and 4 windows from the CPU bus to PCI MEM space. + * We'll only use one PCI MEM window on each PCI bus. + * + * This is the CPU physical memory map (windows must be at least 1MB + * and start on a boundary that is a multiple of the window size): + * + * 0xff800000-0xffffffff - Boot window + * 0xff000000-0xff000fff - AFIX registers (DevCS2) + * 0xfef00000-0xfef0ffff - Internal MV64x60 registers + * 0xfef40000-0xfef7ffff - Internal SRAM + * 0xfef00000-0xfef0ffff - MV64360 Registers + * 0x70000000-0x7fffffff - soldered flash (DevCS3) + * 0xe8000000-0xe9ffffff - PCI I/O + * 0x80000000-0xbfffffff - PCI MEM + */ + +#ifndef __PPC_PLATFORMS_PPC7D_H +#define __PPC_PLATFORMS_PPC7D_H + +#include <asm/ppcboot.h> + +/***************************************************************************** + * CPU Physical Memory Map setup. + *****************************************************************************/ + +#define PPC7D_BOOT_WINDOW_BASE 0xff800000 +#define PPC7D_AFIX_REG_BASE 0xff000000 +#define PPC7D_INTERNAL_SRAM_BASE 0xfef40000 +#define PPC7D_FLASH_BASE 0x70000000 + +#define PPC7D_BOOT_WINDOW_SIZE_ACTUAL 0x00800000 /* 8MB */ +#define PPC7D_FLASH_SIZE_ACTUAL 0x10000000 /* 256MB */ + +#define PPC7D_BOOT_WINDOW_SIZE max(MV64360_WINDOW_SIZE_MIN, \ + PPC7D_BOOT_WINDOW_SIZE_ACTUAL) +#define PPC7D_FLASH_SIZE max(MV64360_WINDOW_SIZE_MIN, \ + PPC7D_FLASH_SIZE_ACTUAL) +#define PPC7D_AFIX_REG_SIZE max(MV64360_WINDOW_SIZE_MIN, 0xff) + + +#define PPC7D_PCI0_MEM0_START_PROC_ADDR 0x80000000UL +#define PPC7D_PCI0_MEM0_START_PCI_HI_ADDR 0x00000000UL +#define PPC7D_PCI0_MEM0_START_PCI_LO_ADDR 0x80000000UL +#define PPC7D_PCI0_MEM0_SIZE 0x20000000UL +#define PPC7D_PCI0_MEM1_START_PROC_ADDR 0xe8010000UL +#define PPC7D_PCI0_MEM1_START_PCI_HI_ADDR 0x00000000UL +#define PPC7D_PCI0_MEM1_START_PCI_LO_ADDR 0x00000000UL +#define PPC7D_PCI0_MEM1_SIZE 0x000f0000UL +#define PPC7D_PCI0_IO_START_PROC_ADDR 0xe8000000UL +#define PPC7D_PCI0_IO_START_PCI_ADDR 0x00000000UL +#define PPC7D_PCI0_IO_SIZE 0x00010000UL + +#define PPC7D_PCI1_MEM0_START_PROC_ADDR 0xa0000000UL +#define PPC7D_PCI1_MEM0_START_PCI_HI_ADDR 0x00000000UL +#define PPC7D_PCI1_MEM0_START_PCI_LO_ADDR 0xa0000000UL +#define PPC7D_PCI1_MEM0_SIZE 0x20000000UL +#define PPC7D_PCI1_MEM1_START_PROC_ADDR 0xe9800000UL +#define PPC7D_PCI1_MEM1_START_PCI_HI_ADDR 0x00000000UL +#define PPC7D_PCI1_MEM1_START_PCI_LO_ADDR 0x00000000UL +#define PPC7D_PCI1_MEM1_SIZE 0x00800000UL +#define PPC7D_PCI1_IO_START_PROC_ADDR 0xe9000000UL +#define PPC7D_PCI1_IO_START_PCI_ADDR 0x00000000UL +#define PPC7D_PCI1_IO_SIZE 0x00010000UL + +#define PPC7D_DEFAULT_BAUD 9600 +#define PPC7D_MPSC_CLK_SRC 8 /* TCLK */ +#define PPC7D_MPSC_CLK_FREQ 133333333 /* 133.3333... MHz */ + +#define PPC7D_ETH0_PHY_ADDR 8 +#define PPC7D_ETH1_PHY_ADDR 9 +#define PPC7D_ETH2_PHY_ADDR 0 + +#define PPC7D_ETH_TX_QUEUE_SIZE 400 +#define PPC7D_ETH_RX_QUEUE_SIZE 400 + +#define PPC7D_ETH_PORT_CONFIG_VALUE \ + MV64340_ETH_UNICAST_NORMAL_MODE | \ + MV64340_ETH_DEFAULT_RX_QUEUE_0 | \ + MV64340_ETH_DEFAULT_RX_ARP_QUEUE_0 | \ + MV64340_ETH_RECEIVE_BC_IF_NOT_IP_OR_ARP | \ + MV64340_ETH_RECEIVE_BC_IF_IP | \ + MV64340_ETH_RECEIVE_BC_IF_ARP | \ + MV64340_ETH_CAPTURE_TCP_FRAMES_DIS | \ + MV64340_ETH_CAPTURE_UDP_FRAMES_DIS | \ + MV64340_ETH_DEFAULT_RX_TCP_QUEUE_0 | \ + MV64340_ETH_DEFAULT_RX_UDP_QUEUE_0 | \ + MV64340_ETH_DEFAULT_RX_BPDU_QUEUE_0 + +#define PPC7D_ETH_PORT_CONFIG_EXTEND_VALUE \ + MV64340_ETH_SPAN_BPDU_PACKETS_AS_NORMAL | \ + MV64340_ETH_PARTITION_DISABLE + +#define GT_ETH_IPG_INT_RX(value) \ + ((value & 0x3fff) << 8) + +#define PPC7D_ETH_PORT_SDMA_CONFIG_VALUE \ + MV64340_ETH_RX_BURST_SIZE_4_64BIT | \ + GT_ETH_IPG_INT_RX(0) | \ + MV64340_ETH_TX_BURST_SIZE_4_64BIT + +#define PPC7D_ETH_PORT_SERIAL_CONTROL_VALUE \ + MV64340_ETH_ENABLE_AUTO_NEG_FOR_DUPLX | \ + MV64340_ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL | \ + MV64340_ETH_ADV_SYMMETRIC_FLOW_CTRL | \ + MV64340_ETH_FORCE_FC_MODE_NO_PAUSE_DIS_TX | \ + MV64340_ETH_FORCE_BP_MODE_NO_JAM | \ + (1 << 9) | \ + MV64340_ETH_DO_NOT_FORCE_LINK_FAIL | \ + MV64340_ETH_RETRANSMIT_16_ATTEMPTS | \ + MV64340_ETH_ENABLE_AUTO_NEG_SPEED_GMII | \ + MV64340_ETH_DTE_ADV_0 | \ + MV64340_ETH_DISABLE_AUTO_NEG_BYPASS | \ + MV64340_ETH_AUTO_NEG_NO_CHANGE | \ + MV64340_ETH_MAX_RX_PACKET_9700BYTE | \ + MV64340_ETH_CLR_EXT_LOOPBACK | \ + MV64340_ETH_SET_FULL_DUPLEX_MODE | \ + MV64340_ETH_ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX + +/***************************************************************************** + * Serial defines. + *****************************************************************************/ + +#define PPC7D_SERIAL_0 0xe80003f8 +#define PPC7D_SERIAL_1 0xe80002f8 + +#define RS_TABLE_SIZE 2 + +/* Rate for the 1.8432 Mhz clock for the onboard serial chip */ +#define UART_CLK 1843200 +#define BASE_BAUD ( UART_CLK / 16 ) + +#ifdef CONFIG_SERIAL_DETECT_IRQ +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ) +#else +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF) +#endif + +#define STD_SERIAL_PORT_DFNS \ + { 0, BASE_BAUD, PPC7D_SERIAL_0, 4, STD_COM_FLAGS, /* ttyS0 */ \ + iomem_base: (u8 *)PPC7D_SERIAL_0, \ + io_type: SERIAL_IO_MEM, }, \ + { 0, BASE_BAUD, PPC7D_SERIAL_1, 3, STD_COM_FLAGS, /* ttyS1 */ \ + iomem_base: (u8 *)PPC7D_SERIAL_1, \ + io_type: SERIAL_IO_MEM }, + +#define SERIAL_PORT_DFNS \ + STD_SERIAL_PORT_DFNS + +/***************************************************************************** + * CPLD defines. + * + * Register map:- + * + * 0000 to 000F South Bridge DMA 1 Control + * 0020 and 0021 South Bridge Interrupt 1 Control + * 0040 to 0043 South Bridge Counter Control + * 0060 Keyboard + * 0061 South Bridge NMI Status and Control + * 0064 Keyboard + * 0071 and 0072 RTC R/W + * 0078 to 007B South Bridge BIOS Timer + * 0080 to 0090 South Bridge DMA Pages + * 00A0 and 00A1 South Bridge Interrupt 2 Control + * 00C0 to 00DE South Bridge DMA 2 Control + * 02E8 to 02EF COM6 R/W + * 02F8 to 02FF South Bridge COM2 R/W + * 03E8 to 03EF COM5 R/W + * 03F8 to 03FF South Bridge COM1 R/W + * 040A South Bridge DMA Scatter/Gather RO + * 040B DMA 1 Extended Mode WO + * 0410 to 043F South Bridge DMA Scatter/Gather + * 0481 to 048B South Bridge DMA High Pages + * 04D0 and 04D1 South Bridge Edge/Level Control + * 04D6 DMA 2 Extended Mode WO + * 0804 Memory Configuration RO + * 0806 Memory Configuration Extend RO + * 0808 SCSI Activity LED R/W + * 080C Equipment Present 1 RO + * 080E Equipment Present 2 RO + * 0810 Equipment Present 3 RO + * 0812 Equipment Present 4 RO + * 0818 Key Lock RO + * 0820 LEDS R/W + * 0824 COMs R/W + * 0826 RTS R/W + * 0828 Reset R/W + * 082C Watchdog Trig R/W + * 082E Interrupt R/W + * 0830 Interrupt Status RO + * 0832 PCI configuration RO + * 0854 Board Revision RO + * 0858 Extended ID RO + * 0864 ID Link RO + * 0866 Motherboard Type RO + * 0868 FLASH Write control RO + * 086A Software FLASH write protect R/W + * 086E FLASH Control R/W + *****************************************************************************/ + +#define PPC7D_CPLD_MEM_CONFIG 0x0804 +#define PPC7D_CPLD_MEM_CONFIG_EXTEND 0x0806 +#define PPC7D_CPLD_SCSI_ACTIVITY_LED 0x0808 +#define PPC7D_CPLD_EQUIPMENT_PRESENT_1 0x080C +#define PPC7D_CPLD_EQUIPMENT_PRESENT_2 0x080E +#define PPC7D_CPLD_EQUIPMENT_PRESENT_3 0x0810 +#define PPC7D_CPLD_EQUIPMENT_PRESENT_4 0x0812 +#define PPC7D_CPLD_KEY_LOCK 0x0818 +#define PPC7D_CPLD_LEDS 0x0820 +#define PPC7D_CPLD_COMS 0x0824 +#define PPC7D_CPLD_RTS 0x0826 +#define PPC7D_CPLD_RESET 0x0828 +#define PPC7D_CPLD_WATCHDOG_TRIG 0x082C +#define PPC7D_CPLD_INTR 0x082E +#define PPC7D_CPLD_INTR_STATUS 0x0830 +#define PPC7D_CPLD_PCI_CONFIG 0x0832 +#define PPC7D_CPLD_BOARD_REVISION 0x0854 +#define PPC7D_CPLD_EXTENDED_ID 0x0858 +#define PPC7D_CPLD_ID_LINK 0x0864 +#define PPC7D_CPLD_MOTHERBOARD_TYPE 0x0866 +#define PPC7D_CPLD_FLASH_WRITE_CNTL 0x0868 +#define PPC7D_CPLD_SW_FLASH_WRITE_PROTECT 0x086A +#define PPC7D_CPLD_FLASH_CNTL 0x086E + +/* MEMORY_CONFIG_EXTEND */ +#define PPC7D_CPLD_SDRAM_BANK_SIZE_MASK 0xc0 +#define PPC7D_CPLD_SDRAM_BANK_SIZE_128M 0 +#define PPC7D_CPLD_SDRAM_BANK_SIZE_256M 0x40 +#define PPC7D_CPLD_SDRAM_BANK_SIZE_512M 0x80 +#define PPC7D_CPLD_SDRAM_BANK_SIZE_1G 0xc0 +#define PPC7D_CPLD_FLASH_DEV_SIZE_MASK 0x03 +#define PPC7D_CPLD_FLASH_BANK_NUM_MASK 0x0c +#define PPC7D_CPLD_FLASH_DEV_SIZE_64M 0 +#define PPC7D_CPLD_FLASH_DEV_SIZE_32M 1 +#define PPC7D_CPLD_FLASH_DEV_SIZE_16M 3 +#define PPC7D_CPLD_FLASH_BANK_NUM_4 0x00 +#define PPC7D_CPLD_FLASH_BANK_NUM_3 0x04 +#define PPC7D_CPLD_FLASH_BANK_NUM_2 0x08 +#define PPC7D_CPLD_FLASH_BANK_NUM_1 0x0c + +/* SCSI_LED */ +#define PPC7D_CPLD_SCSI_ACTIVITY_LED_OFF 0 +#define PPC7D_CPLD_SCSI_ACTIVITY_LED_ON 1 + +/* EQUIPMENT_PRESENT_1 */ +#define PPC7D_CPLD_EQPT_PRES_1_FITTED 0 +#define PPC7D_CPLD_EQPT_PRES_1_PMC2_MASK (0x80 >> 2) +#define PPC7D_CPLD_EQPT_PRES_1_PMC1_MASK (0x80 >> 3) +#define PPC7D_CPLD_EQPT_PRES_1_AFIX_MASK (0x80 >> 4) + +/* EQUIPMENT_PRESENT_2 */ +#define PPC7D_CPLD_EQPT_PRES_2_FITTED !0 +#define PPC7D_CPLD_EQPT_PRES_2_UNIVERSE_MASK (0x80 >> 0) +#define PPC7D_CPLD_EQPT_PRES_2_COM36_MASK (0x80 >> 2) +#define PPC7D_CPLD_EQPT_PRES_2_GIGE_MASK (0x80 >> 3) +#define PPC7D_CPLD_EQPT_PRES_2_DUALGIGE_MASK (0x80 >> 4) + +/* EQUIPMENT_PRESENT_3 */ +#define PPC7D_CPLD_EQPT_PRES_3_PMC2_V_MASK (0x80 >> 3) +#define PPC7D_CPLD_EQPT_PRES_3_PMC2_5V (0 >> 3) +#define PPC7D_CPLD_EQPT_PRES_3_PMC2_3V (0x80 >> 3) +#define PPC7D_CPLD_EQPT_PRES_3_PMC1_V_MASK (0x80 >> 4) +#define PPC7D_CPLD_EQPT_PRES_3_PMC1_5V (0 >> 4) +#define PPC7D_CPLD_EQPT_PRES_3_PMC1_3V (0x80 >> 4) +#define PPC7D_CPLD_EQPT_PRES_3_PMC_POWER_MASK (0x80 >> 5) +#define PPC7D_CPLD_EQPT_PRES_3_PMC_POWER_INTER (0 >> 5) +#define PPC7D_CPLD_EQPT_PRES_3_PMC_POWER_VME (0x80 >> 5) + +/* EQUIPMENT_PRESENT_4 */ +#define PPC7D_CPLD_EQPT_PRES_4_LPT_MASK (0x80 >> 2) +#define PPC7D_CPLD_EQPT_PRES_4_LPT_FITTED (0x80 >> 2) +#define PPC7D_CPLD_EQPT_PRES_4_PS2_USB2_MASK (0xc0 >> 6) +#define PPC7D_CPLD_EQPT_PRES_4_PS2_FITTED (0x40 >> 6) +#define PPC7D_CPLD_EQPT_PRES_4_USB2_FITTED (0x80 >> 6) + +/* CPLD_LEDS */ +#define PPC7D_CPLD_LEDS_ON (!0) +#define PPC7D_CPLD_LEDS_OFF (0) +#define PPC7D_CPLD_LEDS_NVRAM_PAGE_MASK (0xc0 >> 2) +#define PPC7D_CPLD_LEDS_DS201_MASK (0x80 >> 4) +#define PPC7D_CPLD_LEDS_DS219_MASK (0x80 >> 5) +#define PPC7D_CPLD_LEDS_DS220_MASK (0x80 >> 6) +#define PPC7D_CPLD_LEDS_DS221_MASK (0x80 >> 7) + +/* CPLD_COMS */ +#define PPC7D_CPLD_COMS_COM3_TCLKEN (0x80 >> 0) +#define PPC7D_CPLD_COMS_COM3_RTCLKEN (0x80 >> 1) +#define PPC7D_CPLD_COMS_COM3_MODE_MASK (0x80 >> 2) +#define PPC7D_CPLD_COMS_COM3_MODE_RS232 (0) +#define PPC7D_CPLD_COMS_COM3_MODE_RS422 (0x80 >> 2) +#define PPC7D_CPLD_COMS_COM3_TXEN (0x80 >> 3) +#define PPC7D_CPLD_COMS_COM4_TCLKEN (0x80 >> 4) +#define PPC7D_CPLD_COMS_COM4_RTCLKEN (0x80 >> 5) +#define PPC7D_CPLD_COMS_COM4_MODE_MASK (0x80 >> 6) +#define PPC7D_CPLD_COMS_COM4_MODE_RS232 (0) +#define PPC7D_CPLD_COMS_COM4_MODE_RS422 (0x80 >> 6) +#define PPC7D_CPLD_COMS_COM4_TXEN (0x80 >> 7) + +/* CPLD_RTS */ +#define PPC7D_CPLD_RTS_COM36_LOOPBACK (0x80 >> 0) +#define PPC7D_CPLD_RTS_COM4_SCLK (0x80 >> 1) +#define PPC7D_CPLD_RTS_COM3_TXFUNC_MASK (0xc0 >> 2) +#define PPC7D_CPLD_RTS_COM3_TXFUNC_DISABLED (0 >> 2) +#define PPC7D_CPLD_RTS_COM3_TXFUNC_ENABLED (0x80 >> 2) +#define PPC7D_CPLD_RTS_COM3_TXFUNC_ENABLED_RTG3 (0xc0 >> 2) +#define PPC7D_CPLD_RTS_COM3_TXFUNC_ENABLED_RTG3S (0xc0 >> 2) +#define PPC7D_CPLD_RTS_COM56_MODE_MASK (0x80 >> 4) +#define PPC7D_CPLD_RTS_COM56_MODE_RS232 (0) +#define PPC7D_CPLD_RTS_COM56_MODE_RS422 (0x80 >> 4) +#define PPC7D_CPLD_RTS_COM56_ENABLE_MASK (0x80 >> 5) +#define PPC7D_CPLD_RTS_COM56_DISABLED (0) +#define PPC7D_CPLD_RTS_COM56_ENABLED (0x80 >> 5) +#define PPC7D_CPLD_RTS_COM4_TXFUNC_MASK (0xc0 >> 6) +#define PPC7D_CPLD_RTS_COM4_TXFUNC_DISABLED (0 >> 6) +#define PPC7D_CPLD_RTS_COM4_TXFUNC_ENABLED (0x80 >> 6) +#define PPC7D_CPLD_RTS_COM4_TXFUNC_ENABLED_RTG3 (0x40 >> 6) +#define PPC7D_CPLD_RTS_COM4_TXFUNC_ENABLED_RTG3S (0x40 >> 6) + +/* WATCHDOG_TRIG */ +#define PPC7D_CPLD_WDOG_CAUSE_MASK (0x80 >> 0) +#define PPC7D_CPLD_WDOG_CAUSE_NORMAL_RESET (0 >> 0) +#define PPC7D_CPLD_WDOG_CAUSE_WATCHDOG (0x80 >> 0) +#define PPC7D_CPLD_WDOG_ENABLE_MASK (0x80 >> 6) +#define PPC7D_CPLD_WDOG_ENABLE_OFF (0 >> 6) +#define PPC7D_CPLD_WDOG_ENABLE_ON (0x80 >> 6) +#define PPC7D_CPLD_WDOG_RESETSW_MASK (0x80 >> 7) +#define PPC7D_CPLD_WDOG_RESETSW_OFF (0 >> 7) +#define PPC7D_CPLD_WDOG_RESETSW_ON (0x80 >> 7) + +/* Interrupt mask and status bits */ +#define PPC7D_CPLD_INTR_TEMP_MASK (0x80 >> 0) +#define PPC7D_CPLD_INTR_HB8_MASK (0x80 >> 1) +#define PPC7D_CPLD_INTR_PHY1_MASK (0x80 >> 2) +#define PPC7D_CPLD_INTR_PHY0_MASK (0x80 >> 3) +#define PPC7D_CPLD_INTR_ISANMI_MASK (0x80 >> 5) +#define PPC7D_CPLD_INTR_CRITTEMP_MASK (0x80 >> 6) + +/* CPLD_INTR */ +#define PPC7D_CPLD_INTR_ENABLE_OFF (0) +#define PPC7D_CPLD_INTR_ENABLE_ON (!0) + +/* CPLD_INTR_STATUS */ +#define PPC7D_CPLD_INTR_STATUS_OFF (0) +#define PPC7D_CPLD_INTR_STATUS_ON (!0) + +/* CPLD_PCI_CONFIG */ +#define PPC7D_CPLD_PCI_CONFIG_PCI0_MASK 0x70 +#define PPC7D_CPLD_PCI_CONFIG_PCI0_PCI33 0x00 +#define PPC7D_CPLD_PCI_CONFIG_PCI0_PCI66 0x10 +#define PPC7D_CPLD_PCI_CONFIG_PCI0_PCIX33 0x40 +#define PPC7D_CPLD_PCI_CONFIG_PCI0_PCIX66 0x50 +#define PPC7D_CPLD_PCI_CONFIG_PCI0_PCIX100 0x60 +#define PPC7D_CPLD_PCI_CONFIG_PCI0_PCIX133 0x70 +#define PPC7D_CPLD_PCI_CONFIG_PCI1_MASK 0x07 +#define PPC7D_CPLD_PCI_CONFIG_PCI1_PCI33 0x00 +#define PPC7D_CPLD_PCI_CONFIG_PCI1_PCI66 0x01 +#define PPC7D_CPLD_PCI_CONFIG_PCI1_PCIX33 0x04 +#define PPC7D_CPLD_PCI_CONFIG_PCI1_PCIX66 0x05 +#define PPC7D_CPLD_PCI_CONFIG_PCI1_PCIX100 0x06 +#define PPC7D_CPLD_PCI_CONFIG_PCI1_PCIX133 0x07 + +/* CPLD_BOARD_REVISION */ +#define PPC7D_CPLD_BOARD_REVISION_NUMBER_MASK 0xe0 +#define PPC7D_CPLD_BOARD_REVISION_LETTER_MASK 0x1f + +/* CPLD_EXTENDED_ID */ +#define PPC7D_CPLD_EXTENDED_ID_PPC7D 0x18 + +/* CPLD_ID_LINK */ +#define PPC7D_CPLD_ID_LINK_VME64_GAP_MASK (0x80 >> 2) +#define PPC7D_CPLD_ID_LINK_VME64_GA4_MASK (0x80 >> 3) +#define PPC7D_CPLD_ID_LINK_E13_MASK (0x80 >> 4) +#define PPC7D_CPLD_ID_LINK_E12_MASK (0x80 >> 5) +#define PPC7D_CPLD_ID_LINK_E7_MASK (0x80 >> 6) +#define PPC7D_CPLD_ID_LINK_E6_MASK (0x80 >> 7) + +/* CPLD_MOTHERBOARD_TYPE */ +#define PPC7D_CPLD_MB_TYPE_ECC_ENABLE_MASK (0x80 >> 0) +#define PPC7D_CPLD_MB_TYPE_ECC_ENABLED (0x80 >> 0) +#define PPC7D_CPLD_MB_TYPE_ECC_DISABLED (0 >> 0) +#define PPC7D_CPLD_MB_TYPE_ECC_FITTED_MASK (0x80 >> 3) +#define PPC7D_CPLD_MB_TYPE_PLL_MASK 0x0c +#define PPC7D_CPLD_MB_TYPE_PLL_133 0x00 +#define PPC7D_CPLD_MB_TYPE_PLL_100 0x08 +#define PPC7D_CPLD_MB_TYPE_PLL_64 0x04 +#define PPC7D_CPLD_MB_TYPE_HW_ID_MASK 0x03 + +/* CPLD_FLASH_WRITE_CNTL */ +#define PPD7D_CPLD_FLASH_CNTL_WR_LINK_MASK (0x80 >> 0) +#define PPD7D_CPLD_FLASH_CNTL_WR_LINK_FITTED (0x80 >> 0) +#define PPD7D_CPLD_FLASH_CNTL_BOOT_LINK_MASK (0x80 >> 2) +#define PPD7D_CPLD_FLASH_CNTL_BOOT_LINK_FITTED (0x80 >> 2) +#define PPD7D_CPLD_FLASH_CNTL_USER_LINK_MASK (0x80 >> 3) +#define PPD7D_CPLD_FLASH_CNTL_USER_LINK_FITTED (0x80 >> 3) +#define PPD7D_CPLD_FLASH_CNTL_RECO_WR_MASK (0x80 >> 5) +#define PPD7D_CPLD_FLASH_CNTL_RECO_WR_ENABLED (0x80 >> 5) +#define PPD7D_CPLD_FLASH_CNTL_BOOT_WR_MASK (0x80 >> 6) +#define PPD7D_CPLD_FLASH_CNTL_BOOT_WR_ENABLED (0x80 >> 6) +#define PPD7D_CPLD_FLASH_CNTL_USER_WR_MASK (0x80 >> 7) +#define PPD7D_CPLD_FLASH_CNTL_USER_WR_ENABLED (0x80 >> 7) + +/* CPLD_SW_FLASH_WRITE_PROTECT */ +#define PPC7D_CPLD_SW_FLASH_WRPROT_ENABLED (!0) +#define PPC7D_CPLD_SW_FLASH_WRPROT_DISABLED (0) +#define PPC7D_CPLD_SW_FLASH_WRPROT_SYSBOOT_MASK (0x80 >> 6) +#define PPC7D_CPLD_SW_FLASH_WRPROT_USER_MASK (0x80 >> 7) + +/* CPLD_FLASH_WRITE_CNTL */ +#define PPC7D_CPLD_FLASH_CNTL_NVRAM_PROT_MASK (0x80 >> 0) +#define PPC7D_CPLD_FLASH_CNTL_NVRAM_DISABLED (0 >> 0) +#define PPC7D_CPLD_FLASH_CNTL_NVRAM_ENABLED (0x80 >> 0) +#define PPC7D_CPLD_FLASH_CNTL_ALTBOOT_LINK_MASK (0x80 >> 1) +#define PPC7D_CPLD_FLASH_CNTL_VMEBOOT_LINK_MASK (0x80 >> 2) +#define PPC7D_CPLD_FLASH_CNTL_RECBOOT_LINK_MASK (0x80 >> 3) + + +#endif /* __PPC_PLATFORMS_PPC7D_H */ diff --git a/arch/ppc/platforms/residual.c b/arch/ppc/platforms/residual.c new file mode 100644 index 00000000000..0f84ca60361 --- /dev/null +++ b/arch/ppc/platforms/residual.c @@ -0,0 +1,1034 @@ +/* + * Code to deal with the PReP residual data. + * + * Written by: Cort Dougan (cort@cs.nmt.edu) + * Improved _greatly_ and rewritten by Gabriel Paubert (paubert@iram.es) + * + * This file is based on the following documentation: + * + * IBM Power Personal Systems Architecture + * Residual Data + * Document Number: PPS-AR-FW0001 + * + * 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 <linux/string.h> +#include <asm/residual.h> +#include <asm/pnp.h> +#include <asm/byteorder.h> + +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/stddef.h> +#include <linux/unistd.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/user.h> +#include <linux/a.out.h> +#include <linux/tty.h> +#include <linux/major.h> +#include <linux/interrupt.h> +#include <linux/reboot.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/pci.h> +#include <linux/ide.h> + +#include <asm/sections.h> +#include <asm/mmu.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/ide.h> + + +unsigned char __res[sizeof(RESIDUAL)] __prepdata = {0,}; +RESIDUAL *res = (RESIDUAL *)&__res; + +char * PnP_BASE_TYPES[] __initdata = { + "Reserved", + "MassStorageDevice", + "NetworkInterfaceController", + "DisplayController", + "MultimediaController", + "MemoryController", + "BridgeController", + "CommunicationsDevice", + "SystemPeripheral", + "InputDevice", + "ServiceProcessor" + }; + +/* Device Sub Type Codes */ + +unsigned char * PnP_SUB_TYPES[] __initdata = { + "\001\000SCSIController", + "\001\001IDEController", + "\001\002FloppyController", + "\001\003IPIController", + "\001\200OtherMassStorageController", + "\002\000EthernetController", + "\002\001TokenRingController", + "\002\002FDDIController", + "\002\0x80OtherNetworkController", + "\003\000VGAController", + "\003\001SVGAController", + "\003\002XGAController", + "\003\200OtherDisplayController", + "\004\000VideoController", + "\004\001AudioController", + "\004\200OtherMultimediaController", + "\005\000RAM", + "\005\001FLASH", + "\005\200OtherMemoryDevice", + "\006\000HostProcessorBridge", + "\006\001ISABridge", + "\006\002EISABridge", + "\006\003MicroChannelBridge", + "\006\004PCIBridge", + "\006\005PCMCIABridge", + "\006\006VMEBridge", + "\006\200OtherBridgeDevice", + "\007\000RS232Device", + "\007\001ATCompatibleParallelPort", + "\007\200OtherCommunicationsDevice", + "\010\000ProgrammableInterruptController", + "\010\001DMAController", + "\010\002SystemTimer", + "\010\003RealTimeClock", + "\010\004L2Cache", + "\010\005NVRAM", + "\010\006PowerManagement", + "\010\007CMOS", + "\010\010OperatorPanel", + "\010\011ServiceProcessorClass1", + "\010\012ServiceProcessorClass2", + "\010\013ServiceProcessorClass3", + "\010\014GraphicAssist", + "\010\017SystemPlanar", + "\010\200OtherSystemPeripheral", + "\011\000KeyboardController", + "\011\001Digitizer", + "\011\002MouseController", + "\011\003TabletController", + "\011\0x80OtherInputController", + "\012\000GeneralMemoryController", + NULL +}; + +/* Device Interface Type Codes */ + +unsigned char * PnP_INTERFACES[] __initdata = { + "\000\000\000General", + "\001\000\000GeneralSCSI", + "\001\001\000GeneralIDE", + "\001\001\001ATACompatible", + + "\001\002\000GeneralFloppy", + "\001\002\001Compatible765", + "\001\002\002NS398_Floppy", /* NS Super I/O wired to use index + register at port 398 and data + register at port 399 */ + "\001\002\003NS26E_Floppy", /* Ports 26E and 26F */ + "\001\002\004NS15C_Floppy", /* Ports 15C and 15D */ + "\001\002\005NS2E_Floppy", /* Ports 2E and 2F */ + "\001\002\006CHRP_Floppy", /* CHRP Floppy in PR*P system */ + + "\001\003\000GeneralIPI", + + "\002\000\000GeneralEther", + "\002\001\000GeneralToken", + "\002\002\000GeneralFDDI", + + "\003\000\000GeneralVGA", + "\003\001\000GeneralSVGA", + "\003\002\000GeneralXGA", + + "\004\000\000GeneralVideo", + "\004\001\000GeneralAudio", + "\004\001\001CS4232Audio", /* CS 4232 Plug 'n Play Configured */ + + "\005\000\000GeneralRAM", + /* This one is obviously wrong ! */ + "\005\000\000PCIMemoryController", /* PCI Config Method */ + "\005\000\001RS6KMemoryController", /* RS6K Config Method */ + "\005\001\000GeneralFLASH", + + "\006\000\000GeneralHostBridge", + "\006\001\000GeneralISABridge", + "\006\002\000GeneralEISABridge", + "\006\003\000GeneralMCABridge", + /* GeneralPCIBridge = 0, */ + "\006\004\000PCIBridgeDirect", + "\006\004\001PCIBridgeIndirect", + "\006\004\002PCIBridgeRS6K", + "\006\005\000GeneralPCMCIABridge", + "\006\006\000GeneralVMEBridge", + + "\007\000\000GeneralRS232", + "\007\000\001COMx", + "\007\000\002Compatible16450", + "\007\000\003Compatible16550", + "\007\000\004NS398SerPort", /* NS Super I/O wired to use index + register at port 398 and data + register at port 399 */ + "\007\000\005NS26ESerPort", /* Ports 26E and 26F */ + "\007\000\006NS15CSerPort", /* Ports 15C and 15D */ + "\007\000\007NS2ESerPort", /* Ports 2E and 2F */ + + "\007\001\000GeneralParPort", + "\007\001\001LPTx", + "\007\001\002NS398ParPort", /* NS Super I/O wired to use index + register at port 398 and data + register at port 399 */ + "\007\001\003NS26EParPort", /* Ports 26E and 26F */ + "\007\001\004NS15CParPort", /* Ports 15C and 15D */ + "\007\001\005NS2EParPort", /* Ports 2E and 2F */ + + "\010\000\000GeneralPIC", + "\010\000\001ISA_PIC", + "\010\000\002EISA_PIC", + "\010\000\003MPIC", + "\010\000\004RS6K_PIC", + + "\010\001\000GeneralDMA", + "\010\001\001ISA_DMA", + "\010\001\002EISA_DMA", + + "\010\002\000GeneralTimer", + "\010\002\001ISA_Timer", + "\010\002\002EISA_Timer", + "\010\003\000GeneralRTC", + "\010\003\001ISA_RTC", + + "\010\004\001StoreThruOnly", + "\010\004\002StoreInEnabled", + "\010\004\003RS6KL2Cache", + + "\010\005\000IndirectNVRAM", /* Indirectly addressed */ + "\010\005\001DirectNVRAM", /* Memory Mapped */ + "\010\005\002IndirectNVRAM24", /* Indirectly addressed - 24 bit */ + + "\010\006\000GeneralPowerManagement", + "\010\006\001EPOWPowerManagement", + "\010\006\002PowerControl", // d1378 + + "\010\007\000GeneralCMOS", + + "\010\010\000GeneralOPPanel", + "\010\010\001HarddiskLight", + "\010\010\002CDROMLight", + "\010\010\003PowerLight", + "\010\010\004KeyLock", + "\010\010\005ANDisplay", /* AlphaNumeric Display */ + "\010\010\006SystemStatusLED", /* 3 digit 7 segment LED */ + "\010\010\007CHRP_SystemStatusLED", /* CHRP LEDs in PR*P system */ + + "\010\011\000GeneralServiceProcessor", + "\010\012\000GeneralServiceProcessor", + "\010\013\000GeneralServiceProcessor", + + "\010\014\001TransferData", + "\010\014\002IGMC32", + "\010\014\003IGMC64", + + "\010\017\000GeneralSystemPlanar", /* 10/5/95 */ + NULL + }; + +static const unsigned char __init *PnP_SUB_TYPE_STR(unsigned char BaseType, + unsigned char SubType) { + unsigned char ** s=PnP_SUB_TYPES; + while (*s && !((*s)[0]==BaseType + && (*s)[1]==SubType)) s++; + if (*s) return *s+2; + else return("Unknown !"); +}; + +static const unsigned char __init *PnP_INTERFACE_STR(unsigned char BaseType, + unsigned char SubType, + unsigned char Interface) { + unsigned char ** s=PnP_INTERFACES; + while (*s && !((*s)[0]==BaseType + && (*s)[1]==SubType + && (*s)[2]==Interface)) s++; + if (*s) return *s+3; + else return NULL; +}; + +static void __init printsmallvendor(PnP_TAG_PACKET *pkt, int size) { + int i, c; + char decomp[4]; +#define p pkt->S14_Pack.S14_Data.S14_PPCPack + switch(p.Type) { + case 1: + /* Decompress first 3 chars */ + c = *(unsigned short *)p.PPCData; + decomp[0]='A'-1+((c>>10)&0x1F); + decomp[1]='A'-1+((c>>5)&0x1F); + decomp[2]='A'-1+(c&0x1F); + decomp[3]=0; + printk(" Chip identification: %s%4.4X\n", + decomp, ld_le16((unsigned short *)(p.PPCData+2))); + break; + default: + printk(" Small vendor item type 0x%2.2x, data (hex): ", + p.Type); + for(i=0; i<size-2; i++) printk("%2.2x ", p.PPCData[i]); + printk("\n"); + break; + } +#undef p +} + +static void __init printsmallpacket(PnP_TAG_PACKET * pkt, int size) { + static const unsigned char * intlevel[] = {"high", "low"}; + static const unsigned char * intsense[] = {"edge", "level"}; + + switch (tag_small_item_name(pkt->S1_Pack.Tag)) { + case PnPVersion: + printk(" PnPversion 0x%x.%x\n", + pkt->S1_Pack.Version[0], /* How to interpret version ? */ + pkt->S1_Pack.Version[1]); + break; +// case Logicaldevice: + break; +// case CompatibleDevice: + break; + case IRQFormat: +#define p pkt->S4_Pack + printk(" IRQ Mask 0x%4.4x, %s %s sensitive\n", + ld_le16((unsigned short *)p.IRQMask), + intlevel[(size>3) ? !(p.IRQInfo&0x05) : 0], + intsense[(size>3) ? !(p.IRQInfo&0x03) : 0]); +#undef p + break; + case DMAFormat: +#define p pkt->S5_Pack + printk(" DMA channel mask 0x%2.2x, info 0x%2.2x\n", + p.DMAMask, p.DMAInfo); +#undef p + break; + case StartDepFunc: + printk("Start dependent function:\n"); + break; + case EndDepFunc: + printk("End dependent function\n"); + break; + case IOPort: +#define p pkt->S8_Pack + printk(" Variable (%d decoded bits) I/O port\n" + " from 0x%4.4x to 0x%4.4x, alignment %d, %d ports\n", + p.IOInfo&ISAAddr16bit?16:10, + ld_le16((unsigned short *)p.RangeMin), + ld_le16((unsigned short *)p.RangeMax), + p.IOAlign, p.IONum); +#undef p + break; + case FixedIOPort: +#define p pkt->S9_Pack + printk(" Fixed (10 decoded bits) I/O port from %3.3x to %3.3x\n", + (p.Range[1]<<8)|p.Range[0], + ((p.Range[1]<<8)|p.Range[0])+p.IONum-1); +#undef p + break; + case Res1: + case Res2: + case Res3: + printk(" Undefined packet type %d!\n", + tag_small_item_name(pkt->S1_Pack.Tag)); + break; + case SmallVendorItem: + printsmallvendor(pkt,size); + break; + default: + printk(" Type 0x2.2x%d, size=%d\n", + pkt->S1_Pack.Tag, size); + break; + } +} + +static void __init printlargevendor(PnP_TAG_PACKET * pkt, int size) { + static const unsigned char * addrtype[] = {"I/O", "Memory", "System"}; + static const unsigned char * inttype[] = {"8259", "MPIC", "RS6k BUID %d"}; + static const unsigned char * convtype[] = {"Bus Memory", "Bus I/O", "DMA"}; + static const unsigned char * transtype[] = {"direct", "mapped", "direct-store segment"}; + static const unsigned char * L2type[] = {"WriteThru", "CopyBack"}; + static const unsigned char * L2assoc[] = {"DirectMapped", "2-way set"}; + + int i; + char tmpstr[30], *t; +#define p pkt->L4_Pack.L4_Data.L4_PPCPack + switch(p.Type) { + case 2: + printk(" %d K %s %s L2 cache, %d/%d bytes line/sector size\n", + ld_le32((unsigned int *)p.PPCData), + L2type[p.PPCData[10]-1], + L2assoc[p.PPCData[4]-1], + ld_le16((unsigned short *)p.PPCData+3), + ld_le16((unsigned short *)p.PPCData+4)); + break; + case 3: + printk(" PCI Bridge parameters\n" + " ConfigBaseAddress %0x\n" + " ConfigBaseData %0x\n" + " Bus number %d\n", + ld_le32((unsigned int *)p.PPCData), + ld_le32((unsigned int *)(p.PPCData+8)), + p.PPCData[16]); + for(i=20; i<size-4; i+=12) { + int j, first; + if(p.PPCData[i]) printk(" PCI Slot %d", p.PPCData[i]); + else printk (" Integrated PCI device"); + for(j=0, first=1, t=tmpstr; j<4; j++) { + int line=ld_le16((unsigned short *)(p.PPCData+i+4)+j); + if(line!=0xffff){ + if(first) first=0; else *t++='/'; + *t++='A'+j; + } + } + *t='\0'; + printk(" DevFunc 0x%x interrupt line(s) %s routed to", + p.PPCData[i+1],tmpstr); + sprintf(tmpstr, + inttype[p.PPCData[i+2]-1], + p.PPCData[i+3]); + printk(" %s line(s) ", + tmpstr); + for(j=0, first=1, t=tmpstr; j<4; j++) { + int line=ld_le16((unsigned short *)(p.PPCData+i+4)+j); + if(line!=0xffff){ + if(first) first=0; else *t++='/'; + t+=sprintf(t,"%d(%c)", + line&0x7fff, + line&0x8000?'E':'L'); + } + } + printk("%s\n",tmpstr); + } + break; + case 5: + printk(" Bridge address translation, %s decoding:\n" + " Processor Bus Size Conversion Translation\n" + " 0x%8.8x 0x%8.8x 0x%8.8x %s %s\n", + p.PPCData[0]&1 ? "positive" : "subtractive", + ld_le32((unsigned int *)p.PPCData+1), + ld_le32((unsigned int *)p.PPCData+3), + ld_le32((unsigned int *)p.PPCData+5), + convtype[p.PPCData[2]-1], + transtype[p.PPCData[1]-1]); + break; + case 6: + printk(" Bus speed %d Hz, %d slot(s)\n", + ld_le32((unsigned int *)p.PPCData), + p.PPCData[4]); + break; + case 7: + printk(" SCSI buses: %d, id(s):", p.PPCData[0]); + for(i=1; i<=p.PPCData[0]; i++) + printk(" %d%c", p.PPCData[i], i==p.PPCData[0] ? '\n' : ','); + break; + case 9: + printk(" %s address (%d bits), at 0x%x size 0x%x bytes\n", + addrtype[p.PPCData[0]-1], + p.PPCData[1], + ld_le32((unsigned int *)(p.PPCData+4)), + ld_le32((unsigned int *)(p.PPCData+12))); + break; + case 10: + sprintf(tmpstr, + inttype[p.PPCData[0]-1], + p.PPCData[1]); + + printk(" ISA interrupts routed to %s\n" + " lines", + tmpstr); + for(i=0; i<16; i++) { + int line=ld_le16((unsigned short *)p.PPCData+i+1); + if (line!=0xffff) printk(" %d(IRQ%d)", line, i); + } + printk("\n"); + break; + default: + printk(" Large vendor item type 0x%2.2x\n Data (hex):", + p.Type); + for(i=0; i<size-4; i++) printk(" %2.2x", p.PPCData[i]); + printk("\n"); +#undef p + } +} + +static void __init printlargepacket(PnP_TAG_PACKET * pkt, int size) { + switch (tag_large_item_name(pkt->S1_Pack.Tag)) { + case LargeVendorItem: + printlargevendor(pkt, size); + break; + default: + printk(" Type 0x2.2x%d, size=%d\n", + pkt->S1_Pack.Tag, size); + break; + } +} + +static void __init printpackets(PnP_TAG_PACKET * pkt, const char * cat) +{ + if (pkt->S1_Pack.Tag== END_TAG) { + printk(" No packets describing %s resources.\n", cat); + return; + } + printk( " Packets describing %s resources:\n",cat); + do { + int size; + if (tag_type(pkt->S1_Pack.Tag)) { + size= 3 + + pkt->L1_Pack.Count0 + + pkt->L1_Pack.Count1*256; + printlargepacket(pkt, size); + } else { + size=tag_small_count(pkt->S1_Pack.Tag)+1; + printsmallpacket(pkt, size); + } + pkt = (PnP_TAG_PACKET *)((unsigned char *) pkt + size); + } while (pkt->S1_Pack.Tag != END_TAG); +} + +void __init print_residual_device_info(void) +{ + int i; + PPC_DEVICE *dev; +#define did dev->DeviceId + + /* make sure we have residual data first */ + if (!have_residual_data) + return; + + printk("Residual: %ld devices\n", res->ActualNumDevices); + for ( i = 0; + i < res->ActualNumDevices ; + i++) + { + char decomp[4], sn[20]; + const char * s; + dev = &res->Devices[i]; + s = PnP_INTERFACE_STR(did.BaseType, did.SubType, + did.Interface); + if(!s) { + sprintf(sn, "interface %d", did.Interface); + s=sn; + } + if ( did.BusId & PCIDEVICE ) + printk("PCI Device, Bus %d, DevFunc 0x%x:", + dev->BusAccess.PCIAccess.BusNumber, + dev->BusAccess.PCIAccess.DevFuncNumber); + if ( did.BusId & PNPISADEVICE ) printk("PNPISA Device:"); + if ( did.BusId & ISADEVICE ) + printk("ISA Device, Slot %d, LogicalDev %d:", + dev->BusAccess.ISAAccess.SlotNumber, + dev->BusAccess.ISAAccess.LogicalDevNumber); + if ( did.BusId & EISADEVICE ) printk("EISA Device:"); + if ( did.BusId & PROCESSORDEVICE ) + printk("ProcBus Device, Bus %d, BUID %d: ", + dev->BusAccess.ProcBusAccess.BusNumber, + dev->BusAccess.ProcBusAccess.BUID); + if ( did.BusId & PCMCIADEVICE ) printk("PCMCIA "); + if ( did.BusId & VMEDEVICE ) printk("VME "); + if ( did.BusId & MCADEVICE ) printk("MCA "); + if ( did.BusId & MXDEVICE ) printk("MX "); + /* Decompress first 3 chars */ + decomp[0]='A'-1+((did.DevId>>26)&0x1F); + decomp[1]='A'-1+((did.DevId>>21)&0x1F); + decomp[2]='A'-1+((did.DevId>>16)&0x1F); + decomp[3]=0; + printk(" %s%4.4lX, %s, %s, %s\n", + decomp, did.DevId&0xffff, + PnP_BASE_TYPES[did.BaseType], + PnP_SUB_TYPE_STR(did.BaseType,did.SubType), + s); + if ( dev->AllocatedOffset ) + printpackets( (union _PnP_TAG_PACKET *) + &res->DevicePnPHeap[dev->AllocatedOffset], + "allocated"); + if ( dev->PossibleOffset ) + printpackets( (union _PnP_TAG_PACKET *) + &res->DevicePnPHeap[dev->PossibleOffset], + "possible"); + if ( dev->CompatibleOffset ) + printpackets( (union _PnP_TAG_PACKET *) + &res->DevicePnPHeap[dev->CompatibleOffset], + "compatible"); + } +} + + +#if 0 +static void __init printVPD(void) { +#define vpd res->VitalProductData + int ps=vpd.PageSize, i, j; + static const char* Usage[]={ + "FirmwareStack", "FirmwareHeap", "FirmwareCode", "BootImage", + "Free", "Unpopulated", "ISAAddr", "PCIConfig", + "IOMemory", "SystemIO", "SystemRegs", "PCIAddr", + "UnPopSystemRom", "SystemROM", "ResumeBlock", "Other" + }; + static const unsigned char *FWMan[]={ + "IBM", "Motorola", "FirmWorks", "Bull" + }; + static const unsigned char *FWFlags[]={ + "Conventional", "OpenFirmware", "Diagnostics", "LowDebug", + "MultiBoot", "LowClient", "Hex41", "FAT", + "ISO9660", "SCSI_ID_Override", "Tape_Boot", "FW_Boot_Path" + }; + static const unsigned char *ESM[]={ + "Port92", "PCIConfigA8", "FF001030", "????????" + }; + static const unsigned char *SIOM[]={ + "Port850", "????????", "PCIConfigA8", "????????" + }; + + printk("Model: %s\n",vpd.PrintableModel); + printk("Serial: %s\n", vpd.Serial); + printk("FirmwareSupplier: %s\n", FWMan[vpd.FirmwareSupplier]); + printk("FirmwareFlags:"); + for(j=0; j<12; j++) { + if (vpd.FirmwareSupports & (1<<j)) { + printk(" %s%c", FWFlags[j], + vpd.FirmwareSupports&(-2<<j) ? ',' : '\n'); + } + } + printk("NVRamSize: %ld\n", vpd.NvramSize); + printk("SIMMslots: %ld\n", vpd.NumSIMMSlots); + printk("EndianSwitchMethod: %s\n", + ESM[vpd.EndianSwitchMethod>2 ? 2 : vpd.EndianSwitchMethod]); + printk("SpreadIOMethod: %s\n", + SIOM[vpd.SpreadIOMethod>3 ? 3 : vpd.SpreadIOMethod]); + printk("Processor/Bus frequencies (Hz): %ld/%ld\n", + vpd.ProcessorHz, vpd.ProcessorBusHz); + printk("Time Base Divisor: %ld\n", vpd.TimeBaseDivisor); + printk("WordWidth, PageSize: %ld, %d\n", vpd.WordWidth, ps); + printk("Cache sector size, Lock granularity: %ld, %ld\n", + vpd.CoherenceBlockSize, vpd.GranuleSize); + for (i=0; i<res->ActualNumMemSegs; i++) { + int mask=res->Segs[i].Usage, first, j; + printk("%8.8lx-%8.8lx ", + res->Segs[i].BasePage*ps, + (res->Segs[i].PageCount+res->Segs[i].BasePage)*ps-1); + for(j=15, first=1; j>=0; j--) { + if (mask&(1<<j)) { + if (first) first=0; + else printk(", "); + printk("%s", Usage[j]); + } + } + printk("\n"); + } +} + +/* + * Spit out some info about residual data + */ +void print_residual_device_info(void) +{ + int i; + union _PnP_TAG_PACKET *pkt; + PPC_DEVICE *dev; +#define did dev->DeviceId + + /* make sure we have residual data first */ + if (!have_residual_data) + return; + printk("Residual: %ld devices\n", res->ActualNumDevices); + for ( i = 0; + i < res->ActualNumDevices ; + i++) + { + dev = &res->Devices[i]; + /* + * pci devices + */ + if ( did.BusId & PCIDEVICE ) + { + printk("PCI Device:"); + /* unknown vendor */ + if ( !strncmp( "Unknown", pci_strvendor(did.DevId>>16), 7) ) + printk(" id %08lx types %d/%d", did.DevId, + did.BaseType, did.SubType); + /* known vendor */ + else + printk(" %s %s", + pci_strvendor(did.DevId>>16), + pci_strdev(did.DevId>>16, + did.DevId&0xffff) + ); + + if ( did.BusId & PNPISADEVICE ) + { + printk(" pnp:"); + /* get pnp info on the device */ + pkt = (union _PnP_TAG_PACKET *) + &res->DevicePnPHeap[dev->AllocatedOffset]; + for (; pkt->S1_Pack.Tag != DF_END_TAG; + pkt++ ) + { + if ( (pkt->S1_Pack.Tag == S4_Packet) || + (pkt->S1_Pack.Tag == S4_Packet_flags) ) + printk(" irq %02x%02x", + pkt->S4_Pack.IRQMask[0], + pkt->S4_Pack.IRQMask[1]); + } + } + printk("\n"); + continue; + } + /* + * isa devices + */ + if ( did.BusId & ISADEVICE ) + { + printk("ISA Device: basetype: %d subtype: %d", + did.BaseType, did.SubType); + printk("\n"); + continue; + } + /* + * eisa devices + */ + if ( did.BusId & EISADEVICE ) + { + printk("EISA Device: basetype: %d subtype: %d", + did.BaseType, did.SubType); + printk("\n"); + continue; + } + /* + * proc bus devices + */ + if ( did.BusId & PROCESSORDEVICE ) + { + printk("ProcBus Device: basetype: %d subtype: %d", + did.BaseType, did.SubType); + printk("\n"); + continue; + } + /* + * pcmcia devices + */ + if ( did.BusId & PCMCIADEVICE ) + { + printk("PCMCIA Device: basetype: %d subtype: %d", + did.BaseType, did.SubType); + printk("\n"); + continue; + } + printk("Unknown bus access device: busid %lx\n", + did.BusId); + } +} +#endif + +/* Returns the device index in the residual data, + any of the search items may be set as -1 for wildcard, + DevID number field (second halfword) is big endian ! + + Examples: + - search for the Interrupt controller (8259 type), 2 methods: + 1) i8259 = residual_find_device(~0, + NULL, + SystemPeripheral, + ProgrammableInterruptController, + ISA_PIC, + 0); + 2) i8259 = residual_find_device(~0, "PNP0000", -1, -1, -1, 0) + + - search for the first two serial devices, whatever their type) + iserial1 = residual_find_device(~0,NULL, + CommunicationsDevice, + RS232Device, + -1, 0) + iserial2 = residual_find_device(~0,NULL, + CommunicationsDevice, + RS232Device, + -1, 1) + - but search for typical COM1 and COM2 is not easy due to the + fact that the interface may be anything and the name "PNP0500" or + "PNP0501". Quite bad. + +*/ + +/* devid are easier to uncompress than to compress, so to minimize bloat +in this rarely used area we unencode and compare */ + +/* in residual data number is big endian in the device table and +little endian in the heap, so we use two parameters to avoid writing +two very similar functions */ + +static int __init same_DevID(unsigned short vendor, + unsigned short Number, + char * str) +{ + static unsigned const char hexdigit[]="0123456789ABCDEF"; + if (strlen(str)!=7) return 0; + if ( ( ((vendor>>10)&0x1f)+'A'-1 == str[0]) && + ( ((vendor>>5)&0x1f)+'A'-1 == str[1]) && + ( (vendor&0x1f)+'A'-1 == str[2]) && + (hexdigit[(Number>>12)&0x0f] == str[3]) && + (hexdigit[(Number>>8)&0x0f] == str[4]) && + (hexdigit[(Number>>4)&0x0f] == str[5]) && + (hexdigit[Number&0x0f] == str[6]) ) return 1; + return 0; +} + +PPC_DEVICE __init *residual_find_device(unsigned long BusMask, + unsigned char * DevID, + int BaseType, + int SubType, + int Interface, + int n) +{ + int i; + if (!have_residual_data) return NULL; + for (i=0; i<res->ActualNumDevices; i++) { +#define Dev res->Devices[i].DeviceId + if ( (Dev.BusId&BusMask) && + (BaseType==-1 || Dev.BaseType==BaseType) && + (SubType==-1 || Dev.SubType==SubType) && + (Interface==-1 || Dev.Interface==Interface) && + (DevID==NULL || same_DevID((Dev.DevId>>16)&0xffff, + Dev.DevId&0xffff, DevID)) && + !(n--) ) return res->Devices+i; +#undef Dev + } + return NULL; +} + +PPC_DEVICE __init *residual_find_device_id(unsigned long BusMask, + unsigned short DevID, + int BaseType, + int SubType, + int Interface, + int n) +{ + int i; + if (!have_residual_data) return NULL; + for (i=0; i<res->ActualNumDevices; i++) { +#define Dev res->Devices[i].DeviceId + if ( (Dev.BusId&BusMask) && + (BaseType==-1 || Dev.BaseType==BaseType) && + (SubType==-1 || Dev.SubType==SubType) && + (Interface==-1 || Dev.Interface==Interface) && + (DevID==0xffff || (Dev.DevId&0xffff) == DevID) && + !(n--) ) return res->Devices+i; +#undef Dev + } + return NULL; +} + +static int __init +residual_scan_pcibridge(PnP_TAG_PACKET * pkt, struct pci_dev *dev) +{ + int irq = -1; + +#define data pkt->L4_Pack.L4_Data.L4_PPCPack.PPCData + if (dev->bus->number == data[16]) { + int i, size; + + size = 3 + ld_le16((u_short *) (&pkt->L4_Pack.Count0)); + for (i = 20; i < size - 4; i += 12) { + unsigned char pin; + int line_irq; + + if (dev->devfn != data[i + 1]) + continue; + + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + if (pin) { + line_irq = ld_le16((unsigned short *) + (&data[i + 4 + 2 * (pin - 1)])); + irq = (line_irq == 0xffff) ? 0 + : line_irq & 0x7fff; + } else + irq = 0; + + break; + } + } +#undef data + + return irq; +} + +int __init +residual_pcidev_irq(struct pci_dev *dev) +{ + int i = 0; + int irq = -1; + PPC_DEVICE *bridge; + + while ((bridge = residual_find_device + (-1, NULL, BridgeController, PCIBridge, -1, i++))) { + + PnP_TAG_PACKET *pkt; + if (bridge->AllocatedOffset) { + pkt = PnP_find_large_vendor_packet(res->DevicePnPHeap + + bridge->AllocatedOffset, 3, 0); + if (!pkt) + continue; + + irq = residual_scan_pcibridge(pkt, dev); + if (irq != -1) + break; + } + } + + return (irq < 0) ? 0 : irq; +} + +void __init residual_irq_mask(char *irq_edge_mask_lo, char *irq_edge_mask_hi) +{ + PPC_DEVICE *dev; + int i = 0; + unsigned short irq_mask = 0x000; /* default to edge */ + + while ((dev = residual_find_device(-1, NULL, -1, -1, -1, i++))) { + PnP_TAG_PACKET *pkt; + unsigned short mask; + int size; + int offset = dev->AllocatedOffset; + + if (!offset) + continue; + + pkt = PnP_find_packet(res->DevicePnPHeap + offset, + IRQFormat, 0); + if (!pkt) + continue; + + size = tag_small_count(pkt->S1_Pack.Tag) + 1; + mask = ld_le16((unsigned short *)pkt->S4_Pack.IRQMask); + if (size > 3 && (pkt->S4_Pack.IRQInfo & 0x0c)) + irq_mask |= mask; + } + + *irq_edge_mask_lo = irq_mask & 0xff; + *irq_edge_mask_hi = irq_mask >> 8; +} + +unsigned int __init residual_isapic_addr(void) +{ + PPC_DEVICE *isapic; + PnP_TAG_PACKET *pkt; + unsigned int addr; + + isapic = residual_find_device(~0, NULL, SystemPeripheral, + ProgrammableInterruptController, + ISA_PIC, 0); + if (!isapic) + goto unknown; + + pkt = PnP_find_large_vendor_packet(res->DevicePnPHeap + + isapic->AllocatedOffset, 9, 0); + if (!pkt) + goto unknown; + +#define p pkt->L4_Pack.L4_Data.L4_PPCPack + /* Must be 32-bit system address */ + if (!((p.PPCData[0] == 3) && (p.PPCData[1] == 32))) + goto unknown; + + /* It doesn't seem to work where length != 1 (what can I say? :-/ ) */ + if (ld_le32((unsigned int *)(p.PPCData + 12)) != 1) + goto unknown; + + addr = ld_le32((unsigned int *) (p.PPCData + 4)); +#undef p + return addr; +unknown: + return 0; +} + +PnP_TAG_PACKET *PnP_find_packet(unsigned char *p, + unsigned packet_tag, + int n) +{ + unsigned mask, masked_tag, size; + if(!p) return NULL; + if (tag_type(packet_tag)) mask=0xff; else mask=0xF8; + masked_tag = packet_tag&mask; + for(; *p != END_TAG; p+=size) { + if ((*p & mask) == masked_tag && !(n--)) + return (PnP_TAG_PACKET *) p; + if (tag_type(*p)) + size=ld_le16((unsigned short *)(p+1))+3; + else + size=tag_small_count(*p)+1; + } + return NULL; /* not found */ +} + +PnP_TAG_PACKET __init *PnP_find_small_vendor_packet(unsigned char *p, + unsigned packet_type, + int n) +{ + int next=0; + while (p) { + p = (unsigned char *) PnP_find_packet(p, 0x70, next); + if (p && p[1]==packet_type && !(n--)) + return (PnP_TAG_PACKET *) p; + next = 1; + }; + return NULL; /* not found */ +} + +PnP_TAG_PACKET __init *PnP_find_large_vendor_packet(unsigned char *p, + unsigned packet_type, + int n) +{ + int next=0; + while (p) { + p = (unsigned char *) PnP_find_packet(p, 0x84, next); + if (p && p[3]==packet_type && !(n--)) + return (PnP_TAG_PACKET *) p; + next = 1; + }; + return NULL; /* not found */ +} + +#ifdef CONFIG_PROC_PREPRESIDUAL +static int proc_prep_residual_read(char * buf, char ** start, off_t off, + int count, int *eof, void *data) +{ + int n; + + n = res->ResidualLength - off; + if (n < 0) { + *eof = 1; + n = 0; + } + else { + if (n > count) + n = count; + else + *eof = 1; + + memcpy(buf, (char *)res + off, n); + *start = buf; + } + + return n; +} + +int __init +proc_prep_residual_init(void) +{ + if (have_residual_data) + create_proc_read_entry("residual", S_IRUGO, NULL, + proc_prep_residual_read, NULL); + return 0; +} + +__initcall(proc_prep_residual_init); +#endif diff --git a/arch/ppc/platforms/rpx8260.h b/arch/ppc/platforms/rpx8260.h new file mode 100644 index 00000000000..843494a50ef --- /dev/null +++ b/arch/ppc/platforms/rpx8260.h @@ -0,0 +1,81 @@ +/* + * A collection of structures, addresses, and values associated with + * the Embedded Planet RPX6 (or RPX Super) MPC8260 board. + * Copied from the RPX-Classic and SBS8260 stuff. + * + * Copyright (c) 2001 Dan Malek <dan@embeddededge.com> + */ +#ifdef __KERNEL__ +#ifndef __ASM_PLATFORMS_RPX8260_H__ +#define __ASM_PLATFORMS_RPX8260_H__ + +/* A Board Information structure that is given to a program when + * prom starts it up. + */ +typedef struct bd_info { + unsigned int bi_memstart; /* Memory start address */ + unsigned int bi_memsize; /* Memory (end) size in bytes */ + unsigned int bi_nvsize; /* NVRAM size in bytes (can be 0) */ + unsigned int bi_intfreq; /* Internal Freq, in Hz */ + unsigned int bi_busfreq; /* Bus Freq, in MHz */ + unsigned int bi_cpmfreq; /* CPM Freq, in MHz */ + unsigned int bi_brgfreq; /* BRG Freq, in MHz */ + unsigned int bi_vco; /* VCO Out from PLL */ + unsigned int bi_baudrate; /* Default console baud rate */ + unsigned int bi_immr; /* IMMR when called from boot rom */ + unsigned char bi_enetaddr[6]; +} bd_t; + +extern bd_t m8xx_board_info; + +/* Memory map is configured by the PROM startup. + * We just map a few things we need. The CSR is actually 4 byte-wide + * registers that can be accessed as 8-, 16-, or 32-bit values. + */ +#define CPM_MAP_ADDR ((uint)0xf0000000) +#define RPX_CSR_ADDR ((uint)0xfa000000) +#define RPX_CSR_SIZE ((uint)(512 * 1024)) +#define RPX_NVRTC_ADDR ((uint)0xfa080000) +#define RPX_NVRTC_SIZE ((uint)(512 * 1024)) + +/* The RPX6 has 16, byte wide control/status registers. + * Not all are used (yet). + */ +extern volatile u_char *rpx6_csr_addr; + +/* Things of interest in the CSR. +*/ +#define BCSR0_ID_MASK ((u_char)0xf0) /* Read only */ +#define BCSR0_SWITCH_MASK ((u_char)0x0f) /* Read only */ +#define BCSR1_XCVR_SMC1 ((u_char)0x80) +#define BCSR1_XCVR_SMC2 ((u_char)0x40) +#define BCSR2_FLASH_WENABLE ((u_char)0x20) +#define BCSR2_NVRAM_ENABLE ((u_char)0x10) +#define BCSR2_ALT_IRQ2 ((u_char)0x08) +#define BCSR2_ALT_IRQ3 ((u_char)0x04) +#define BCSR2_PRST ((u_char)0x02) /* Force reset */ +#define BCSR2_ENPRST ((u_char)0x01) /* Enable POR */ +#define BCSR3_MODCLK_MASK ((u_char)0xe0) +#define BCSR3_ENCLKHDR ((u_char)0x10) +#define BCSR3_LED5 ((u_char)0x04) /* 0 == on */ +#define BCSR3_LED6 ((u_char)0x02) /* 0 == on */ +#define BCSR3_LED7 ((u_char)0x01) /* 0 == on */ +#define BCSR4_EN_PHY ((u_char)0x80) /* Enable PHY */ +#define BCSR4_EN_MII ((u_char)0x40) /* Enable PHY */ +#define BCSR4_MII_READ ((u_char)0x04) +#define BCSR4_MII_MDC ((u_char)0x02) +#define BCSR4_MII_MDIO ((u_char)0x01) +#define BCSR13_FETH_IRQMASK ((u_char)0xf0) +#define BCSR15_FETH_IRQ ((u_char)0x20) + +#define PHY_INTERRUPT SIU_INT_IRQ7 + +/* For our show_cpuinfo hooks. */ +#define CPUINFO_VENDOR "Embedded Planet" +#define CPUINFO_MACHINE "EP8260 PowerPC" + +/* Warm reset vector. */ +#define BOOTROM_RESTART_ADDR ((uint)0xfff00104) + +#endif /* __ASM_PLATFORMS_RPX8260_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/rpxclassic.h b/arch/ppc/platforms/rpxclassic.h new file mode 100644 index 00000000000..6daa109491c --- /dev/null +++ b/arch/ppc/platforms/rpxclassic.h @@ -0,0 +1,119 @@ +/* + * A collection of structures, addresses, and values associated with + * the RPCG RPX-Classic board. Copied from the RPX-Lite stuff. + * + * Copyright (c) 1998 Dan Malek (dmalek@jlc.net) + */ +#ifdef __KERNEL__ +#ifndef __MACH_RPX_DEFS +#define __MACH_RPX_DEFS + +#include <linux/config.h> + +#ifndef __ASSEMBLY__ +/* A Board Information structure that is given to a program when + * prom starts it up. + */ +typedef struct bd_info { + unsigned int bi_memstart; /* Memory start address */ + unsigned int bi_memsize; /* Memory (end) size in bytes */ + unsigned int bi_intfreq; /* Internal Freq, in Hz */ + unsigned int bi_busfreq; /* Bus Freq, in Hz */ + unsigned char bi_enetaddr[6]; + unsigned int bi_baudrate; +} bd_t; + +extern bd_t m8xx_board_info; + +/* Memory map is configured by the PROM startup. + * We just map a few things we need. The CSR is actually 4 byte-wide + * registers that can be accessed as 8-, 16-, or 32-bit values. + */ +#define PCI_ISA_IO_ADDR ((unsigned)0x80000000) +#define PCI_ISA_IO_SIZE ((uint)(512 * 1024 * 1024)) +#define PCI_ISA_MEM_ADDR ((unsigned)0xc0000000) +#define PCI_ISA_MEM_SIZE ((uint)(512 * 1024 * 1024)) +#define RPX_CSR_ADDR ((uint)0xfa400000) +#define RPX_CSR_SIZE ((uint)(4 * 1024)) +#define IMAP_ADDR ((uint)0xfa200000) +#define IMAP_SIZE ((uint)(64 * 1024)) +#define PCI_CSR_ADDR ((uint)0x80000000) +#define PCI_CSR_SIZE ((uint)(64 * 1024)) +#define PCMCIA_MEM_ADDR ((uint)0xe0000000) +#define PCMCIA_MEM_SIZE ((uint)(64 * 1024)) +#define PCMCIA_IO_ADDR ((uint)0xe4000000) +#define PCMCIA_IO_SIZE ((uint)(4 * 1024)) +#define PCMCIA_ATTRB_ADDR ((uint)0xe8000000) +#define PCMCIA_ATTRB_SIZE ((uint)(4 * 1024)) + +/* Things of interest in the CSR. +*/ +#define BCSR0_ETHEN ((uint)0x80000000) +#define BCSR0_ETHLPBK ((uint)0x40000000) +#define BCSR0_COLTESTDIS ((uint)0x20000000) +#define BCSR0_FULLDPLXDIS ((uint)0x10000000) +#define BCSR0_ENFLSHSEL ((uint)0x04000000) +#define BCSR0_FLASH_SEL ((uint)0x02000000) +#define BCSR0_ENMONXCVR ((uint)0x01000000) + +#define BCSR0_PCMCIAVOLT ((uint)0x000f0000) /* CLLF */ +#define BCSR0_PCMCIA3VOLT ((uint)0x000a0000) /* CLLF */ +#define BCSR0_PCMCIA5VOLT ((uint)0x00060000) /* CLLF */ + +#define BCSR1_IPB5SEL ((uint)0x00100000) +#define BCSR1_PCVCTL4 ((uint)0x00080000) +#define BCSR1_PCVCTL5 ((uint)0x00040000) +#define BCSR1_PCVCTL6 ((uint)0x00020000) +#define BCSR1_PCVCTL7 ((uint)0x00010000) + +#define BCSR2_EN232XCVR ((uint)0x00008000) +#define BCSR2_QSPACESEL ((uint)0x00004000) +#define BCSR2_FETHLEDMODE ((uint)0x00000800) /* CLLF */ + +#if defined(CONFIG_HTDMSOUND) +#include <platforms/rpxhiox.h> +#endif + +/* define IO_BASE for pcmcia, CLLF only */ +#if !defined(CONFIG_PCI) +#define _IO_BASE 0x80000000 +#define _IO_BASE_SIZE 0x1000 + +/* for pcmcia sandisk */ +#ifdef CONFIG_IDE +# define MAX_HWIFS 1 +#endif +#endif + +/* Interrupt level assignments. +*/ +#define FEC_INTERRUPT SIU_LEVEL1 /* FEC interrupt */ + + +/* CPM Ethernet through SCCx. + * + * Bits in parallel I/O port registers that have to be set/cleared + * to configure the pins for SCC1 use. + */ +#define PA_ENET_RXD ((ushort)0x0001) +#define PA_ENET_TXD ((ushort)0x0002) +#define PA_ENET_TCLK ((ushort)0x0200) +#define PA_ENET_RCLK ((ushort)0x0800) +#define PB_ENET_TENA ((uint)0x00001000) +#define PC_ENET_CLSN ((ushort)0x0010) +#define PC_ENET_RENA ((ushort)0x0020) + +/* Control bits in the SICR to route TCLK (CLK2) and RCLK (CLK4) to + * SCC1. Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero. + */ +#define SICR_ENET_MASK ((uint)0x000000ff) +#define SICR_ENET_CLKRT ((uint)0x0000003d) + +/* We don't use the 8259. +*/ + +#define NR_8259_INTS 0 + +#endif /* !__ASSEMBLY__ */ +#endif /* __MACH_RPX_DEFS */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/rpxhiox.h b/arch/ppc/platforms/rpxhiox.h new file mode 100644 index 00000000000..c3fa5a65376 --- /dev/null +++ b/arch/ppc/platforms/rpxhiox.h @@ -0,0 +1,41 @@ +/* + * The Embedded Planet HIOX expansion card definitions. + * There were a few different versions of these cards, but only + * the one that escaped real production is defined here. + * + * Copyright (c) 2000 Dan Malek (dmalek@jlc.net) + */ +#ifndef __MACH_RPX_HIOX_DEFS +#define __MACH_RPX_HIOX_DEFS + +#define HIOX_CSR_ADDR ((uint)0xfac00000) +#define HIOX_CSR_SIZE ((uint)(4 * 1024)) +#define HIOX_CSR0_ADDR HIOX_CSR_ADDR +#define HIOX_CSR4_ADDR ((uint)0xfac00004) + +#define HIOX_CSR0_DEFAULT ((uint)0x380f3c00) +#define HIOX_CSR0_ENSCC2 ((uint)0x80000000) +#define HIOX_CSR0_ENSMC2 ((uint)0x04000000) +#define HIOX_CSR0_ENVDOCLK ((uint)0x02000000) +#define HIOX_CSR0_VDORST_HL ((uint)0x01000000) +#define HIOX_CSR0_RS232SEL ((uint)0x0000c000) +#define HIOX_CSR0_SCC3SEL ((uint)0x0000c000) +#define HIOX_CSR0_SMC1SEL ((uint)0x00008000) +#define HIOX_CSR0_SCC1SEL ((uint)0x00004000) +#define HIOX_CSR0_ENTOUCH ((uint)0x00000080) +#define HIOX_CSR0_PDOWN100 ((uint)0x00000060) +#define HIOX_CSR0_PDOWN10 ((uint)0x00000040) +#define HIOX_CSR0_PDOWN1 ((uint)0x00000020) +#define HIOX_CSR0_TSELSPI ((uint)0x00000010) +#define HIOX_CSR0_TIRQSTAT ((uint)0x00000008) +#define HIOX_CSR4_DEFAULT ((uint)0x00000000) +#define HIOX_CSR4_ENTIRQ2 ((uint)0x20000000) +#define HIOX_CSR4_ENTIRQ3 ((uint)0x10000000) +#define HIOX_CSR4_ENAUDIO ((uint)0x00000080) +#define HIOX_CSR4_RSTAUDIO ((uint)0x00000040) /* 0 == reset */ +#define HIOX_CSR4_AUDCLKHI ((uint)0x00000020) +#define HIOX_CSR4_AUDSPISEL ((uint)0x00000010) +#define HIOX_CSR4_AUDIRQSTAT ((uint)0x00000008) +#define HIOX_CSR4_AUDCLKSEL ((uint)0x00000007) + +#endif diff --git a/arch/ppc/platforms/rpxlite.h b/arch/ppc/platforms/rpxlite.h new file mode 100644 index 00000000000..deee5bd36aa --- /dev/null +++ b/arch/ppc/platforms/rpxlite.h @@ -0,0 +1,96 @@ +/* + * A collection of structures, addresses, and values associated with + * the RPCG RPX-Lite board. Copied from the MBX stuff. + * + * Copyright (c) 1998 Dan Malek (dmalek@jlc.net) + */ +#ifdef __KERNEL__ +#ifndef __MACH_RPX_DEFS +#define __MACH_RPX_DEFS + +#include <linux/config.h> + +#ifndef __ASSEMBLY__ +/* A Board Information structure that is given to a program when + * prom starts it up. + */ +typedef struct bd_info { + unsigned int bi_memstart; /* Memory start address */ + unsigned int bi_memsize; /* Memory (end) size in bytes */ + unsigned int bi_intfreq; /* Internal Freq, in Hz */ + unsigned int bi_busfreq; /* Bus Freq, in Hz */ + unsigned char bi_enetaddr[6]; + unsigned int bi_baudrate; +} bd_t; + +extern bd_t m8xx_board_info; + +/* Memory map is configured by the PROM startup. + * We just map a few things we need. The CSR is actually 4 byte-wide + * registers that can be accessed as 8-, 16-, or 32-bit values. + */ +#define RPX_CSR_ADDR ((uint)0xfa400000) +#define RPX_CSR_SIZE ((uint)(4 * 1024)) +#define IMAP_ADDR ((uint)0xfa200000) +#define IMAP_SIZE ((uint)(64 * 1024)) +#define PCMCIA_MEM_ADDR ((uint)0x04000000) +#define PCMCIA_MEM_SIZE ((uint)(64 * 1024)) +#define PCMCIA_IO_ADDR ((uint)0x04400000) +#define PCMCIA_IO_SIZE ((uint)(4 * 1024)) + +/* Things of interest in the CSR. +*/ +#define BCSR0_ETHEN ((uint)0x80000000) +#define BCSR0_ETHLPBK ((uint)0x40000000) +#define BCSR0_COLTESTDIS ((uint)0x20000000) +#define BCSR0_FULLDPLXDIS ((uint)0x10000000) +#define BCSR0_LEDOFF ((uint)0x08000000) +#define BCSR0_USBDISABLE ((uint)0x04000000) +#define BCSR0_USBHISPEED ((uint)0x02000000) +#define BCSR0_USBPWREN ((uint)0x01000000) +#define BCSR0_PCMCIAVOLT ((uint)0x000f0000) +#define BCSR0_PCMCIA3VOLT ((uint)0x000a0000) +#define BCSR0_PCMCIA5VOLT ((uint)0x00060000) + +#define BCSR1_IPB5SEL ((uint)0x00100000) +#define BCSR1_PCVCTL4 ((uint)0x00080000) +#define BCSR1_PCVCTL5 ((uint)0x00040000) +#define BCSR1_PCVCTL6 ((uint)0x00020000) +#define BCSR1_PCVCTL7 ((uint)0x00010000) + +#if defined(CONFIG_HTDMSOUND) +#include <platforms/rpxhiox.h> +#endif + +/* define IO_BASE for pcmcia */ +#define _IO_BASE 0x80000000 +#define _IO_BASE_SIZE 0x1000 + +#ifdef CONFIG_IDE +# define MAX_HWIFS 1 +#endif + +/* CPM Ethernet through SCCx. + * + * This ENET stuff is for the MPC850 with ethernet on SCC2. Some of + * this may be unique to the RPX-Lite configuration. + * Note TENA is on Port B. + */ +#define PA_ENET_RXD ((ushort)0x0004) +#define PA_ENET_TXD ((ushort)0x0008) +#define PA_ENET_TCLK ((ushort)0x0200) +#define PA_ENET_RCLK ((ushort)0x0800) +#define PB_ENET_TENA ((uint)0x00002000) +#define PC_ENET_CLSN ((ushort)0x0040) +#define PC_ENET_RENA ((ushort)0x0080) + +#define SICR_ENET_MASK ((uint)0x0000ff00) +#define SICR_ENET_CLKRT ((uint)0x00003d00) + +/* We don't use the 8259. +*/ +#define NR_8259_INTS 0 + +#endif /* !__ASSEMBLY__ */ +#endif /* __MACH_RPX_DEFS */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/sandpoint.c b/arch/ppc/platforms/sandpoint.c new file mode 100644 index 00000000000..531bfa0e451 --- /dev/null +++ b/arch/ppc/platforms/sandpoint.c @@ -0,0 +1,742 @@ +/* + * arch/ppc/platforms/sandpoint_setup.c + * + * Board setup routines for the Motorola SPS Sandpoint Test Platform. + * + * Author: Mark A. Greer + * mgreer@mvista.com + * + * 2000-2003 (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. + */ + +/* + * This file adds support for the Motorola SPS Sandpoint Test Platform. + * These boards have a PPMC slot for the processor so any combination + * of cpu and host bridge can be attached. This port is for an 8240 PPMC + * module from Motorola SPS and other closely related cpu/host bridge + * combinations (e.g., 750/755/7400 with MPC107 host bridge). + * The sandpoint itself has a Windbond 83c553 (PCI-ISA bridge, 2 DMA ctlrs, 2 + * cascaded 8259 interrupt ctlrs, 8254 Timer/Counter, and an IDE ctlr), a + * National 87308 (RTC, 2 UARTs, Keyboard & mouse ctlrs, and a floppy ctlr), + * and 4 PCI slots (only 2 of which are usable; the other 2 are keyed for 3.3V + * but are really 5V). + * + * The firmware on the sandpoint is called DINK (not my acronym :). This port + * depends on DINK to do some basic initialization (e.g., initialize the memory + * ctlr) and to ensure that the processor is using MAP B (CHRP map). + * + * The switch settings for the Sandpoint board MUST be as follows: + * S3: down + * S4: up + * S5: up + * S6: down + * + * 'down' is in the direction from the PCI slots towards the PPMC slot; + * 'up' is in the direction from the PPMC slot towards the PCI slots. + * Be careful, the way the sandpoint board is installed in XT chasses will + * make the directions reversed. + * + * Since Motorola listened to our suggestions for improvement, we now have + * the Sandpoint X3 board. All of the PCI slots are available, it uses + * the serial interrupt interface (just a hardware thing we need to + * configure properly). + * + * Use the default X3 switch settings. The interrupts are then: + * EPIC Source + * 0 SIOINT (8259, active low) + * 1 PCI #1 + * 2 PCI #2 + * 3 PCI #3 + * 4 PCI #4 + * 7 Winbond INTC (IDE interrupt) + * 8 Winbond INTD (IDE interrupt) + * + * + * Motorola has finally released a version of DINK32 that correctly + * (seemingly) initalizes the memory controller correctly, regardless + * of the amount of memory in the system. Once a method of determining + * what version of DINK initializes the system for us, if applicable, is + * found, we can hopefully stop hardcoding 32MB of RAM. + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/major.h> +#include <linux/initrd.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/ide.h> +#include <linux/seq_file.h> +#include <linux/root_dev.h> +#include <linux/serial.h> +#include <linux/tty.h> /* for linux/serial_core.h */ +#include <linux/serial_core.h> + +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/time.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/machdep.h> +#include <asm/prom.h> +#include <asm/smp.h> +#include <asm/vga.h> +#include <asm/open_pic.h> +#include <asm/i8259.h> +#include <asm/todc.h> +#include <asm/bootinfo.h> +#include <asm/mpc10x.h> +#include <asm/pci-bridge.h> +#include <asm/kgdb.h> + +#include "sandpoint.h" + +/* Set non-zero if an X2 Sandpoint detected. */ +static int sandpoint_is_x2; + +unsigned char __res[sizeof(bd_t)]; + +static void sandpoint_halt(void); +static void sandpoint_probe_type(void); + +/* + * Define all of the IRQ senses and polarities. Taken from the + * Sandpoint X3 User's manual. + */ +static u_char sandpoint_openpic_initsenses[] __initdata = { + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 0: SIOINT */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 2: PCI Slot 1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 3: PCI Slot 2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 4: PCI Slot 3 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 5: PCI Slot 4 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 8: IDE (INT C) */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE) /* 9: IDE (INT D) */ +}; + +/* + * Motorola SPS Sandpoint interrupt routing. + */ +static inline int +x3_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + { 16, 0, 0, 0 }, /* IDSEL 11 - i8259 on Winbond */ + { 0, 0, 0, 0 }, /* IDSEL 12 - unused */ + { 18, 21, 20, 19 }, /* IDSEL 13 - PCI slot 1 */ + { 19, 18, 21, 20 }, /* IDSEL 14 - PCI slot 2 */ + { 20, 19, 18, 21 }, /* IDSEL 15 - PCI slot 3 */ + { 21, 20, 19, 18 }, /* IDSEL 16 - PCI slot 4 */ + }; + + const long min_idsel = 11, max_idsel = 16, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +} + +static inline int +x2_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + { 18, 0, 0, 0 }, /* IDSEL 11 - i8259 on Windbond */ + { 0, 0, 0, 0 }, /* IDSEL 12 - unused */ + { 16, 17, 18, 19 }, /* IDSEL 13 - PCI slot 1 */ + { 17, 18, 19, 16 }, /* IDSEL 14 - PCI slot 2 */ + { 18, 19, 16, 17 }, /* IDSEL 15 - PCI slot 3 */ + { 19, 16, 17, 18 }, /* IDSEL 16 - PCI slot 4 */ + }; + + const long min_idsel = 11, max_idsel = 16, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +} + +static void __init +sandpoint_setup_winbond_83553(struct pci_controller *hose) +{ + int devfn; + + /* + * Route IDE interrupts directly to the 8259's IRQ 14 & 15. + * We can't route the IDE interrupt to PCI INTC# or INTD# because those + * woule interfere with the PMC's INTC# and INTD# lines. + */ + /* + * Winbond Fcn 0 + */ + devfn = PCI_DEVFN(11,0); + + early_write_config_byte(hose, + 0, + devfn, + 0x43, /* IDE Interrupt Routing Control */ + 0xef); + early_write_config_word(hose, + 0, + devfn, + 0x44, /* PCI Interrupt Routing Control */ + 0x0000); + + /* Want ISA memory cycles to be forwarded to PCI bus */ + early_write_config_byte(hose, + 0, + devfn, + 0x48, /* ISA-to-PCI Addr Decoder Control */ + 0xf0); + + /* Enable Port 92. */ + early_write_config_byte(hose, + 0, + devfn, + 0x4e, /* AT System Control Register */ + 0x06); + /* + * Winbond Fcn 1 + */ + devfn = PCI_DEVFN(11,1); + + /* Put IDE controller into native mode. */ + early_write_config_byte(hose, + 0, + devfn, + 0x09, /* Programming interface Register */ + 0x8f); + + /* Init IRQ routing, enable both ports, disable fast 16 */ + early_write_config_dword(hose, + 0, + devfn, + 0x40, /* IDE Control/Status Register */ + 0x00ff0011); + return; +} + +/* On the sandpoint X2, we must avoid sending configuration cycles to + * device #12 (IDSEL addr = AD12). + */ +static int +x2_exclude_device(u_char bus, u_char devfn) +{ + if ((bus == 0) && (PCI_SLOT(devfn) == SANDPOINT_HOST_BRIDGE_IDSEL)) + return PCIBIOS_DEVICE_NOT_FOUND; + else + return PCIBIOS_SUCCESSFUL; +} + +static void __init +sandpoint_find_bridges(void) +{ + struct pci_controller *hose; + + hose = pcibios_alloc_controller(); + + if (!hose) + return; + + hose->first_busno = 0; + hose->last_busno = 0xff; + + if (mpc10x_bridge_init(hose, + MPC10X_MEM_MAP_B, + MPC10X_MEM_MAP_B, + MPC10X_MAPB_EUMB_BASE) == 0) { + + /* Do early winbond init, then scan PCI bus */ + sandpoint_setup_winbond_83553(hose); + hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); + + ppc_md.pcibios_fixup = NULL; + ppc_md.pcibios_fixup_bus = NULL; + ppc_md.pci_swizzle = common_swizzle; + if (sandpoint_is_x2) { + ppc_md.pci_map_irq = x2_map_irq; + ppc_md.pci_exclude_device = x2_exclude_device; + } else + ppc_md.pci_map_irq = x3_map_irq; + } + else { + if (ppc_md.progress) + ppc_md.progress("Bridge init failed", 0x100); + printk("Host bridge init failed\n"); + } + + return; +} + +static void __init +sandpoint_setup_arch(void) +{ + /* Probe for Sandpoint model */ + sandpoint_probe_type(); + if (sandpoint_is_x2) + epic_serial_mode = 0; + + loops_per_jiffy = 100000000 / HZ; + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_HDA1; +#endif + + /* Lookup PCI host bridges */ + sandpoint_find_bridges(); + + printk(KERN_INFO "Motorola SPS Sandpoint Test Platform\n"); + printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n"); + + /* DINK32 12.3 and below do not correctly enable any caches. + * We will do this now with good known values. Future versions + * of DINK32 are supposed to get this correct. + */ + if (cpu_has_feature(CPU_FTR_SPEC7450)) + /* 745x is different. We only want to pass along enable. */ + _set_L2CR(L2CR_L2E); + else if (cpu_has_feature(CPU_FTR_L2CR)) + /* All modules have 1MB of L2. We also assume that an + * L2 divisor of 3 will work. + */ + _set_L2CR(L2CR_L2E | L2CR_L2SIZ_1MB | L2CR_L2CLK_DIV3 + | L2CR_L2RAM_PIPE | L2CR_L2OH_1_0 | L2CR_L2DF); +#if 0 + /* Untested right now. */ + if (cpu_has_feature(CPU_FTR_L3CR)) { + /* Magic value. */ + _set_L3CR(0x8f032000); + } +#endif +} + +#define SANDPOINT_87308_CFG_ADDR 0x15c +#define SANDPOINT_87308_CFG_DATA 0x15d + +#define SANDPOINT_87308_CFG_INB(addr, byte) { \ + outb((addr), SANDPOINT_87308_CFG_ADDR); \ + (byte) = inb(SANDPOINT_87308_CFG_DATA); \ +} + +#define SANDPOINT_87308_CFG_OUTB(addr, byte) { \ + outb((addr), SANDPOINT_87308_CFG_ADDR); \ + outb((byte), SANDPOINT_87308_CFG_DATA); \ +} + +#define SANDPOINT_87308_SELECT_DEV(dev_num) { \ + SANDPOINT_87308_CFG_OUTB(0x07, (dev_num)); \ +} + +#define SANDPOINT_87308_DEV_ENABLE(dev_num) { \ + SANDPOINT_87308_SELECT_DEV(dev_num); \ + SANDPOINT_87308_CFG_OUTB(0x30, 0x01); \ +} + +/* + * To probe the Sandpoint type, we need to check for a connection between GPIO + * pins 6 and 7 on the NS87308 SuperIO. + */ +static void __init sandpoint_probe_type(void) +{ + u8 x; + /* First, ensure that the GPIO pins are enabled. */ + SANDPOINT_87308_SELECT_DEV(0x07); /* Select GPIO logical device */ + SANDPOINT_87308_CFG_OUTB(0x60, 0x07); /* Base address 0x700 */ + SANDPOINT_87308_CFG_OUTB(0x61, 0x00); + SANDPOINT_87308_CFG_OUTB(0x30, 0x01); /* Enable */ + + /* Now, set pin 7 to output and pin 6 to input. */ + outb((inb(0x701) | 0x80) & 0xbf, 0x701); + /* Set push-pull output */ + outb(inb(0x702) | 0x80, 0x702); + /* Set pull-up on input */ + outb(inb(0x703) | 0x40, 0x703); + /* Set output high and check */ + x = inb(0x700); + outb(x | 0x80, 0x700); + x = inb(0x700); + sandpoint_is_x2 = ! (x & 0x40); + if (ppc_md.progress && sandpoint_is_x2) + ppc_md.progress("High output says X2", 0); + /* Set output low and check */ + outb(x & 0x7f, 0x700); + sandpoint_is_x2 |= inb(0x700) & 0x40; + if (ppc_md.progress && sandpoint_is_x2) + ppc_md.progress("Low output says X2", 0); + if (ppc_md.progress && ! sandpoint_is_x2) + ppc_md.progress("Sandpoint is X3", 0); +} + +/* + * Fix IDE interrupts. + */ +static int __init +sandpoint_fix_winbond_83553(void) +{ + /* Make some 8259 interrupt level sensitive */ + outb(0xe0, 0x4d0); + outb(0xde, 0x4d1); + + return 0; +} + +arch_initcall(sandpoint_fix_winbond_83553); + +/* + * Initialize the ISA devices on the Nat'l PC87308VUL SuperIO chip. + */ +static int __init +sandpoint_setup_natl_87308(void) +{ + u_char reg; + + /* + * Enable all the devices on the Super I/O chip. + */ + SANDPOINT_87308_SELECT_DEV(0x00); /* Select kbd logical device */ + SANDPOINT_87308_CFG_OUTB(0xf0, 0x00); /* Set KBC clock to 8 Mhz */ + SANDPOINT_87308_DEV_ENABLE(0x00); /* Enable keyboard */ + SANDPOINT_87308_DEV_ENABLE(0x01); /* Enable mouse */ + SANDPOINT_87308_DEV_ENABLE(0x02); /* Enable rtc */ + SANDPOINT_87308_DEV_ENABLE(0x03); /* Enable fdc (floppy) */ + SANDPOINT_87308_DEV_ENABLE(0x04); /* Enable parallel */ + SANDPOINT_87308_DEV_ENABLE(0x05); /* Enable UART 2 */ + SANDPOINT_87308_CFG_OUTB(0xf0, 0x82); /* Enable bank select regs */ + SANDPOINT_87308_DEV_ENABLE(0x06); /* Enable UART 1 */ + SANDPOINT_87308_CFG_OUTB(0xf0, 0x82); /* Enable bank select regs */ + + /* Set up floppy in PS/2 mode */ + outb(0x09, SIO_CONFIG_RA); + reg = inb(SIO_CONFIG_RD); + reg = (reg & 0x3F) | 0x40; + outb(reg, SIO_CONFIG_RD); + outb(reg, SIO_CONFIG_RD); /* Have to write twice to change! */ + + return 0; +} + +arch_initcall(sandpoint_setup_natl_87308); + +static int __init +sandpoint_request_io(void) +{ + request_region(0x00,0x20,"dma1"); + request_region(0x20,0x20,"pic1"); + request_region(0x40,0x20,"timer"); + request_region(0x80,0x10,"dma page reg"); + request_region(0xa0,0x20,"pic2"); + request_region(0xc0,0x20,"dma2"); + + return 0; +} + +arch_initcall(sandpoint_request_io); + +/* + * Interrupt setup and service. Interrrupts on the Sandpoint come + * from the four PCI slots plus the 8259 in the Winbond Super I/O (SIO). + * The 8259 is cascaded from EPIC IRQ0, IRQ1-4 map to PCI slots 1-4, + * IDE is on EPIC 7 and 8. + */ +static void __init +sandpoint_init_IRQ(void) +{ + int i; + + OpenPIC_InitSenses = sandpoint_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof(sandpoint_openpic_initsenses); + + mpc10x_set_openpic(); + openpic_hookup_cascade(sandpoint_is_x2 ? 17 : NUM_8259_INTERRUPTS, "82c59 cascade", + i8259_irq); + + /* + * openpic_init() has set up irq_desc[16-31] to be openpic + * interrupts. We need to set irq_desc[0-15] to be i8259 + * interrupts. + */ + for(i=0; i < NUM_8259_INTERRUPTS; i++) + irq_desc[i].handler = &i8259_pic; + + /* + * The EPIC allows for a read in the range of 0xFEF00000 -> + * 0xFEFFFFFF to generate a PCI interrupt-acknowledge transaction. + */ + i8259_init(0xfef00000); +} + +static u32 +sandpoint_irq_canonicalize(u32 irq) +{ + if (irq == 2) + return 9; + else + return irq; +} + +static unsigned long __init +sandpoint_find_end_of_memory(void) +{ + bd_t *bp = (bd_t *)__res; + + if (bp->bi_memsize) + return bp->bi_memsize; + + /* DINK32 13.0 correctly initalizes things, so iff you use + * this you _should_ be able to change this instead of a + * hardcoded value. */ +#if 0 + return mpc10x_get_mem_size(MPC10X_MEM_MAP_B); +#else + return 32*1024*1024; +#endif +} + +static void __init +sandpoint_map_io(void) +{ + io_block_mapping(0xfe000000, 0xfe000000, 0x02000000, _PAGE_IO); +} + +static void +sandpoint_restart(char *cmd) +{ + local_irq_disable(); + + /* Set exception prefix high - to the firmware */ + _nmask_and_or_msr(0, MSR_IP); + + /* Reset system via Port 92 */ + outb(0x00, 0x92); + outb(0x01, 0x92); + for(;;); /* Spin until reset happens */ +} + +static void +sandpoint_power_off(void) +{ + local_irq_disable(); + for(;;); /* No way to shut power off with software */ + /* NOTREACHED */ +} + +static void +sandpoint_halt(void) +{ + sandpoint_power_off(); + /* NOTREACHED */ +} + +static int +sandpoint_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "vendor\t\t: Motorola SPS\n"); + seq_printf(m, "machine\t\t: Sandpoint\n"); + + return 0; +} + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +/* + * IDE support. + */ +static int sandpoint_ide_ports_known = 0; +static unsigned long sandpoint_ide_regbase[MAX_HWIFS]; +static unsigned long sandpoint_ide_ctl_regbase[MAX_HWIFS]; +static unsigned long sandpoint_idedma_regbase; + +static void +sandpoint_ide_probe(void) +{ + struct pci_dev *pdev = pci_get_device(PCI_VENDOR_ID_WINBOND, + PCI_DEVICE_ID_WINBOND_82C105, NULL); + + if (pdev) { + sandpoint_ide_regbase[0]=pdev->resource[0].start; + sandpoint_ide_regbase[1]=pdev->resource[2].start; + sandpoint_ide_ctl_regbase[0]=pdev->resource[1].start; + sandpoint_ide_ctl_regbase[1]=pdev->resource[3].start; + sandpoint_idedma_regbase=pdev->resource[4].start; + pci_dev_put(pdev); + } + + sandpoint_ide_ports_known = 1; +} + +static int +sandpoint_ide_default_irq(unsigned long base) +{ + if (sandpoint_ide_ports_known == 0) + sandpoint_ide_probe(); + + if (base == sandpoint_ide_regbase[0]) + return SANDPOINT_IDE_INT0; + else if (base == sandpoint_ide_regbase[1]) + return SANDPOINT_IDE_INT1; + else + return 0; +} + +static unsigned long +sandpoint_ide_default_io_base(int index) +{ + if (sandpoint_ide_ports_known == 0) + sandpoint_ide_probe(); + + return sandpoint_ide_regbase[index]; +} + +static void __init +sandpoint_ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port, + unsigned long ctrl_port, int *irq) +{ + unsigned long reg = data_port; + uint alt_status_base; + int i; + + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + hw->io_ports[i] = reg++; + } + + if (data_port == sandpoint_ide_regbase[0]) { + alt_status_base = sandpoint_ide_ctl_regbase[0] + 2; + hw->irq = 14; + } + else if (data_port == sandpoint_ide_regbase[1]) { + alt_status_base = sandpoint_ide_ctl_regbase[1] + 2; + hw->irq = 15; + } + else { + alt_status_base = 0; + hw->irq = 0; + } + + if (ctrl_port) { + hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; + } else { + hw->io_ports[IDE_CONTROL_OFFSET] = alt_status_base; + } + + if (irq != NULL) { + *irq = hw->irq; + } +} +#endif + +/* + * Set BAT 3 to map 0xf8000000 to end of physical memory space 1-to-1. + */ +static __inline__ void +sandpoint_set_bat(void) +{ + unsigned long bat3u, bat3l; + + __asm__ __volatile__( + " lis %0,0xf800\n \ + ori %1,%0,0x002a\n \ + ori %0,%0,0x0ffe\n \ + mtspr 0x21e,%0\n \ + mtspr 0x21f,%1\n \ + isync\n \ + sync " + : "=r" (bat3u), "=r" (bat3l)); +} + +TODC_ALLOC(); + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + parse_bootinfo(find_bootinfo()); + + /* ASSUMPTION: If both r3 (bd_t pointer) and r6 (cmdline pointer) + * are non-zero, then we should use the board info from the bd_t + * structure and the cmdline pointed to by r6 instead of the + * information from birecs, if any. Otherwise, use the information + * from birecs as discovered by the preceeding call to + * parse_bootinfo(). This rule should work with both PPCBoot, which + * uses a bd_t board info structure, and the kernel boot wrapper, + * which uses birecs. + */ + if (r3 && r6) { + /* copy board info structure */ + memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) ); + /* copy command line */ + *(char *)(r7+KERNELBASE) = 0; + strcpy(cmd_line, (char *)(r6+KERNELBASE)); + } + +#ifdef CONFIG_BLK_DEV_INITRD + /* take care of initrd if we have one */ + if (r4) { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif /* CONFIG_BLK_DEV_INITRD */ + + /* Map in board regs, etc. */ + sandpoint_set_bat(); + + isa_io_base = MPC10X_MAPB_ISA_IO_BASE; + isa_mem_base = MPC10X_MAPB_ISA_MEM_BASE; + pci_dram_offset = MPC10X_MAPB_DRAM_OFFSET; + ISA_DMA_THRESHOLD = 0x00ffffff; + DMA_MODE_READ = 0x44; + DMA_MODE_WRITE = 0x48; + + ppc_md.setup_arch = sandpoint_setup_arch; + ppc_md.show_cpuinfo = sandpoint_show_cpuinfo; + ppc_md.irq_canonicalize = sandpoint_irq_canonicalize; + ppc_md.init_IRQ = sandpoint_init_IRQ; + ppc_md.get_irq = openpic_get_irq; + + ppc_md.restart = sandpoint_restart; + ppc_md.power_off = sandpoint_power_off; + ppc_md.halt = sandpoint_halt; + + ppc_md.find_end_of_memory = sandpoint_find_end_of_memory; + ppc_md.setup_io_mappings = sandpoint_map_io; + + TODC_INIT(TODC_TYPE_PC97307, 0x70, 0x00, 0x71, 8); + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.calibrate_decr = todc_calibrate_decr; + + ppc_md.nvram_read_val = todc_mc146818_read_val; + ppc_md.nvram_write_val = todc_mc146818_write_val; + +#ifdef CONFIG_KGDB + ppc_md.kgdb_map_scc = gen550_kgdb_map_scc; +#endif +#ifdef CONFIG_SERIAL_TEXT_DEBUG + ppc_md.progress = gen550_progress; +#endif + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) + ppc_ide_md.default_irq = sandpoint_ide_default_irq; + ppc_ide_md.default_io_base = sandpoint_ide_default_io_base; + ppc_ide_md.ide_init_hwif = sandpoint_ide_init_hwif_ports; +#endif +} diff --git a/arch/ppc/platforms/sandpoint.h b/arch/ppc/platforms/sandpoint.h new file mode 100644 index 00000000000..f4e982cb69d --- /dev/null +++ b/arch/ppc/platforms/sandpoint.h @@ -0,0 +1,80 @@ +/* + * arch/ppc/platforms/sandpoint.h + * + * Definitions for Motorola SPS Sandpoint Test Platform + * + * Author: Mark A. Greer + * mgreer@mvista.com + * + * 2000-2003 (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. + */ + +/* + * Sandpoint uses the CHRP map (Map B). + */ + +#ifndef __PPC_PLATFORMS_SANDPOINT_H +#define __PPC_PLATFORMS_SANDPOINT_H + +#include <asm/ppcboot.h> + +#if 0 +/* The Sandpoint X3 allows the IDE interrupt to be directly connected + * from the Windbond (PCI INTC or INTD) to the serial EPIC. Someday + * we should try this, but it was easier to use the existing 83c553 + * initialization than change it to route the different interrupts :-). + * -- Dan + */ +#define SANDPOINT_IDE_INT0 23 /* EPIC 7 */ +#define SANDPOINT_IDE_INT1 24 /* EPIC 8 */ +#else +#define SANDPOINT_IDE_INT0 14 /* 8259 Test */ +#define SANDPOINT_IDE_INT1 15 /* 8259 Test */ +#endif + +/* + * The sandpoint boards have processor modules that either have an 8240 or + * an MPC107 host bridge on them. These bridges have an IDSEL line that allows + * them to respond to PCI transactions as if they were a normal PCI devices. + * However, the processor on the processor side of the bridge can not reach + * out onto the PCI bus and then select the bridge or bad things will happen + * (documented in the 8240 and 107 manuals). + * Because of this, we always skip the bridge PCI device when accessing the + * PCI bus. The PCI slot that the bridge occupies is defined by the macro + * below. + */ +#define SANDPOINT_HOST_BRIDGE_IDSEL 12 + +/* + * Serial defines. + */ +#define SANDPOINT_SERIAL_0 0xfe0003f8 +#define SANDPOINT_SERIAL_1 0xfe0002f8 + +#define RS_TABLE_SIZE 2 + +/* Rate for the 1.8432 Mhz clock for the onboard serial chip */ +#define BASE_BAUD ( 1843200 / 16 ) +#define UART_CLK 1843200 + +#ifdef CONFIG_SERIAL_DETECT_IRQ +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ) +#else +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF) +#endif + +#define STD_SERIAL_PORT_DFNS \ + { 0, BASE_BAUD, SANDPOINT_SERIAL_0, 4, STD_COM_FLAGS, /* ttyS0 */ \ + iomem_base: (u8 *)SANDPOINT_SERIAL_0, \ + io_type: SERIAL_IO_MEM }, \ + { 0, BASE_BAUD, SANDPOINT_SERIAL_1, 3, STD_COM_FLAGS, /* ttyS1 */ \ + iomem_base: (u8 *)SANDPOINT_SERIAL_1, \ + io_type: SERIAL_IO_MEM }, + +#define SERIAL_PORT_DFNS \ + STD_SERIAL_PORT_DFNS + +#endif /* __PPC_PLATFORMS_SANDPOINT_H */ diff --git a/arch/ppc/platforms/sbc82xx.c b/arch/ppc/platforms/sbc82xx.c new file mode 100644 index 00000000000..74c9ff72c3d --- /dev/null +++ b/arch/ppc/platforms/sbc82xx.c @@ -0,0 +1,259 @@ +/* + * arch/ppc/platforms/sbc82xx.c + * + * SBC82XX platform support + * + * Author: Guy Streeter <streeter@redhat.com> + * + * Derived from: est8260_setup.c by Allen Curtis, ONZ + * + * Copyright 2004 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/init.h> +#include <linux/pci.h> + +#include <asm/mpc8260.h> +#include <asm/machdep.h> +#include <asm/io.h> +#include <asm/todc.h> +#include <asm/immap_cpm2.h> +#include <asm/pci.h> + +static void (*callback_init_IRQ)(void); + +extern unsigned char __res[sizeof(bd_t)]; + +extern void (*late_time_init)(void); + +#ifdef CONFIG_GEN_RTC +TODC_ALLOC(); + +/* + * Timer init happens before mem_init but after paging init, so we cannot + * directly use ioremap() at that time. + * late_time_init() is call after paging init. + */ + +static void sbc82xx_time_init(void) +{ + volatile memctl_cpm2_t *mc = &cpm2_immr->im_memctl; + + /* Set up CS11 for RTC chip */ + mc->memc_br11=0; + mc->memc_or11=0xffff0836; + mc->memc_br11=SBC82xx_TODC_NVRAM_ADDR | 0x0801; + + TODC_INIT(TODC_TYPE_MK48T59, 0, 0, SBC82xx_TODC_NVRAM_ADDR, 0); + + todc_info->nvram_data = + (unsigned int)ioremap(todc_info->nvram_data, 0x2000); + BUG_ON(!todc_info->nvram_data); + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; + todc_time_init(); +} +#endif /* CONFIG_GEN_RTC */ + +static volatile char *sbc82xx_i8259_map; +static char sbc82xx_i8259_mask = 0xff; +static DEFINE_SPINLOCK(sbc82xx_i8259_lock); + +static void sbc82xx_i8259_mask_and_ack_irq(unsigned int irq_nr) +{ + unsigned long flags; + + irq_nr -= NR_SIU_INTS; + + spin_lock_irqsave(&sbc82xx_i8259_lock, flags); + sbc82xx_i8259_mask |= 1 << irq_nr; + (void) sbc82xx_i8259_map[1]; /* Dummy read */ + sbc82xx_i8259_map[1] = sbc82xx_i8259_mask; + sbc82xx_i8259_map[0] = 0x20; /* OCW2: Non-specific EOI */ + spin_unlock_irqrestore(&sbc82xx_i8259_lock, flags); +} + +static void sbc82xx_i8259_mask_irq(unsigned int irq_nr) +{ + unsigned long flags; + + irq_nr -= NR_SIU_INTS; + + spin_lock_irqsave(&sbc82xx_i8259_lock, flags); + sbc82xx_i8259_mask |= 1 << irq_nr; + sbc82xx_i8259_map[1] = sbc82xx_i8259_mask; + spin_unlock_irqrestore(&sbc82xx_i8259_lock, flags); +} + +static void sbc82xx_i8259_unmask_irq(unsigned int irq_nr) +{ + unsigned long flags; + + irq_nr -= NR_SIU_INTS; + + spin_lock_irqsave(&sbc82xx_i8259_lock, flags); + sbc82xx_i8259_mask &= ~(1 << irq_nr); + sbc82xx_i8259_map[1] = sbc82xx_i8259_mask; + spin_unlock_irqrestore(&sbc82xx_i8259_lock, flags); +} + +static void sbc82xx_i8259_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) + && irq_desc[irq].action) + sbc82xx_i8259_unmask_irq(irq); +} + + +struct hw_interrupt_type sbc82xx_i8259_ic = { + .typename = " i8259 ", + .enable = sbc82xx_i8259_unmask_irq, + .disable = sbc82xx_i8259_mask_irq, + .ack = sbc82xx_i8259_mask_and_ack_irq, + .end = sbc82xx_i8259_end_irq, +}; + +static irqreturn_t sbc82xx_i8259_demux(int irq, void *dev_id, struct pt_regs *regs) +{ + spin_lock(&sbc82xx_i8259_lock); + + sbc82xx_i8259_map[0] = 0x0c; /* OCW3: Read IR register on RD# pulse */ + irq = sbc82xx_i8259_map[0] & 7; /* Read IRR */ + + if (irq == 7) { + /* Possible spurious interrupt */ + int isr; + sbc82xx_i8259_map[0] = 0x0b; /* OCW3: Read IS register on RD# pulse */ + isr = sbc82xx_i8259_map[0]; /* Read ISR */ + + if (!(isr & 0x80)) { + printk(KERN_INFO "Spurious i8259 interrupt\n"); + return IRQ_HANDLED; + } + } + __do_IRQ(NR_SIU_INTS + irq, regs); + return IRQ_HANDLED; +} + +static struct irqaction sbc82xx_i8259_irqaction = { + .handler = sbc82xx_i8259_demux, + .flags = SA_INTERRUPT, + .mask = CPU_MASK_NONE, + .name = "i8259 demux", +}; + +void __init sbc82xx_init_IRQ(void) +{ + volatile memctl_cpm2_t *mc = &cpm2_immr->im_memctl; + volatile intctl_cpm2_t *ic = &cpm2_immr->im_intctl; + int i; + + callback_init_IRQ(); + + /* u-boot doesn't always set the board up correctly */ + mc->memc_br5 = 0; + mc->memc_or5 = 0xfff00856; + mc->memc_br5 = 0x22000801; + + sbc82xx_i8259_map = ioremap(0x22008000, 2); + if (!sbc82xx_i8259_map) { + printk(KERN_CRIT "Mapping i8259 interrupt controller failed\n"); + return; + } + + /* Set up the interrupt handlers for the i8259 IRQs */ + for (i = NR_SIU_INTS; i < NR_SIU_INTS + 8; i++) { + irq_desc[i].handler = &sbc82xx_i8259_ic; + irq_desc[i].status |= IRQ_LEVEL; + } + + /* make IRQ6 level sensitive */ + ic->ic_siexr &= ~(1 << (14 - (SIU_INT_IRQ6 - SIU_INT_IRQ1))); + irq_desc[SIU_INT_IRQ6].status |= IRQ_LEVEL; + + /* Initialise the i8259 */ + sbc82xx_i8259_map[0] = 0x1b; /* ICW1: Level, no cascade, ICW4 */ + sbc82xx_i8259_map[1] = 0x00; /* ICW2: vector base */ + /* No ICW3 (no cascade) */ + sbc82xx_i8259_map[1] = 0x01; /* ICW4: 8086 mode, normal EOI */ + + sbc82xx_i8259_map[0] = 0x0b; /* OCW3: Read IS register on RD# pulse */ + + sbc82xx_i8259_map[1] = sbc82xx_i8259_mask; /* Set interrupt mask */ + + /* Request cascade IRQ */ + if (setup_irq(SIU_INT_IRQ6, &sbc82xx_i8259_irqaction)) { + printk("Installation of i8259 IRQ demultiplexer failed.\n"); + } +} + +static int sbc82xx_pci_map_irq(struct pci_dev *dev, unsigned char idsel, + unsigned char pin) +{ + static char pci_irq_table[][4] = { + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { SBC82xx_PIRQA, SBC82xx_PIRQB, SBC82xx_PIRQC, SBC82xx_PIRQD }, /* IDSEL 16 - PMC slot */ + { SBC82xx_PC_IRQA, SBC82xx_PC_IRQB, -1, -1 }, /* IDSEL 17 - CardBus */ + { SBC82xx_PIRQA, SBC82xx_PIRQB, SBC82xx_PIRQC, SBC82xx_PIRQD }, /* IDSEL 18 - PCI-X bridge */ + }; + + const long min_idsel = 16, max_idsel = 18, irqs_per_slot = 4; + + return PCI_IRQ_TABLE_LOOKUP; +} + +static void __devinit quirk_sbc8260_cardbus(struct pci_dev *pdev) +{ + uint32_t ctrl; + + if (pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(17, 0)) + return; + + printk(KERN_INFO "Setting up CardBus controller\n"); + + /* Set P2CCLK bit in System Control Register */ + pci_read_config_dword(pdev, 0x80, &ctrl); + ctrl |= (1<<27); + pci_write_config_dword(pdev, 0x80, ctrl); + + /* Set MFUNC up for PCI IRQ routing via INTA and INTB, and LEDs. */ + pci_write_config_dword(pdev, 0x8c, 0x00c01d22); + +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1420, quirk_sbc8260_cardbus); + +void __init +m82xx_board_init(void) +{ + /* u-boot may be using one of the FCC Ethernet devices. + Use the MAC address to the SCC. */ + __res[offsetof(bd_t, bi_enetaddr[5])] &= ~3; + + /* Anything special for this platform */ + callback_init_IRQ = ppc_md.init_IRQ; + + ppc_md.init_IRQ = sbc82xx_init_IRQ; + ppc_md.pci_map_irq = sbc82xx_pci_map_irq; +#ifdef CONFIG_GEN_RTC + ppc_md.time_init = NULL; + ppc_md.get_rtc_time = NULL; + ppc_md.set_rtc_time = NULL; + ppc_md.nvram_read_val = NULL; + ppc_md.nvram_write_val = NULL; + late_time_init = sbc82xx_time_init; +#endif /* CONFIG_GEN_RTC */ +} diff --git a/arch/ppc/platforms/sbc82xx.h b/arch/ppc/platforms/sbc82xx.h new file mode 100644 index 00000000000..e4042d4995f --- /dev/null +++ b/arch/ppc/platforms/sbc82xx.h @@ -0,0 +1,36 @@ +/* Board information for the SBCPowerQUICCII, which should be generic for + * all 8260 boards. The IMMR is now given to us so the hard define + * will soon be removed. All of the clock values are computed from + * the configuration SCMR and the Power-On-Reset word. + */ + +#ifndef __PPC_SBC82xx_H__ +#define __PPC_SBC82xx_H__ + +#include <asm/ppcboot.h> + +#define CPM_MAP_ADDR 0xf0000000 + +#define SBC82xx_TODC_NVRAM_ADDR 0xd0000000 + +#define SBC82xx_MACADDR_NVRAM_FCC1 0x220000c9 /* JP6B */ +#define SBC82xx_MACADDR_NVRAM_SCC1 0x220000cf /* JP6A */ +#define SBC82xx_MACADDR_NVRAM_FCC2 0x220000d5 /* JP7A */ +#define SBC82xx_MACADDR_NVRAM_FCC3 0x220000db /* JP7B */ + +/* For our show_cpuinfo hooks. */ +#define CPUINFO_VENDOR "Wind River" +#define CPUINFO_MACHINE "SBC PowerQUICC II" + +#define BOOTROM_RESTART_ADDR ((uint)0x40000104) + +#define SBC82xx_PC_IRQA (NR_SIU_INTS+0) +#define SBC82xx_PC_IRQB (NR_SIU_INTS+1) +#define SBC82xx_MPC185_IRQ (NR_SIU_INTS+2) +#define SBC82xx_ATM_IRQ (NR_SIU_INTS+3) +#define SBC82xx_PIRQA (NR_SIU_INTS+4) +#define SBC82xx_PIRQB (NR_SIU_INTS+5) +#define SBC82xx_PIRQC (NR_SIU_INTS+6) +#define SBC82xx_PIRQD (NR_SIU_INTS+7) + +#endif /* __PPC_SBC82xx_H__ */ diff --git a/arch/ppc/platforms/sbs8260.h b/arch/ppc/platforms/sbs8260.h new file mode 100644 index 00000000000..d51427a0f0d --- /dev/null +++ b/arch/ppc/platforms/sbs8260.h @@ -0,0 +1,28 @@ +#ifndef __ASSEMBLY__ +/* Board information for various SBS 8260 cards, which should be generic for + * all 8260 boards. The IMMR is now given to us so the hard define + * will soon be removed. All of the clock values are computed from + * the configuration SCMR and the Power-On-Reset word. + */ + +#define CPM_MAP_ADDR ((uint)0xfe000000) + + +/* A Board Information structure that is given to a program when + * prom starts it up. + */ +typedef struct bd_info { + unsigned int bi_memstart; /* Memory start address */ + unsigned int bi_memsize; /* Memory (end) size in bytes */ + unsigned int bi_intfreq; /* Internal Freq, in Hz */ + unsigned int bi_busfreq; /* Bus Freq, in MHz */ + unsigned int bi_cpmfreq; /* CPM Freq, in MHz */ + unsigned int bi_brgfreq; /* BRG Freq, in MHz */ + unsigned int bi_vco; /* VCO Out from PLL */ + unsigned int bi_baudrate; /* Default console baud rate */ + unsigned int bi_immr; /* IMMR when called from boot rom */ + unsigned char bi_enetaddr[6]; +} bd_t; + +extern bd_t m8xx_board_info; +#endif /* !__ASSEMBLY__ */ diff --git a/arch/ppc/platforms/spd8xx.h b/arch/ppc/platforms/spd8xx.h new file mode 100644 index 00000000000..ed48d144f41 --- /dev/null +++ b/arch/ppc/platforms/spd8xx.h @@ -0,0 +1,92 @@ +/* + * Speech Design SPD8xxTS board specific definitions + * + * Copyright (c) 2000,2001 Wolfgang Denk (wd@denx.de) + */ + +#ifdef __KERNEL__ +#ifndef __ASM_SPD8XX_H__ +#define __ASM_SPD8XX_H__ + +#include <linux/config.h> + +#include <asm/ppcboot.h> + +#ifndef __ASSEMBLY__ +#define SPD_IMMR_BASE 0xFFF00000 /* phys. addr of IMMR */ +#define SPD_IMAP_SIZE (64 * 1024) /* size of mapped area */ + +#define IMAP_ADDR SPD_IMMR_BASE /* physical base address of IMMR area */ +#define IMAP_SIZE SPD_IMAP_SIZE /* mapped size of IMMR area */ + +#define PCMCIA_MEM_ADDR ((uint)0xFE100000) +#define PCMCIA_MEM_SIZE ((uint)(64 * 1024)) + +#define IDE0_INTERRUPT 10 /* = IRQ5 */ +#define IDE1_INTERRUPT 12 /* = IRQ6 */ +#define CPM_INTERRUPT 13 /* = SIU_LEVEL6 (was: SIU_LEVEL2) */ + +/* override the default number of IDE hardware interfaces */ +#define MAX_HWIFS 2 + +/* + * Definitions for IDE0 Interface + */ +#define IDE0_BASE_OFFSET 0x0000 /* Offset in PCMCIA memory */ +#define IDE0_DATA_REG_OFFSET 0x0000 +#define IDE0_ERROR_REG_OFFSET 0x0081 +#define IDE0_NSECTOR_REG_OFFSET 0x0082 +#define IDE0_SECTOR_REG_OFFSET 0x0083 +#define IDE0_LCYL_REG_OFFSET 0x0084 +#define IDE0_HCYL_REG_OFFSET 0x0085 +#define IDE0_SELECT_REG_OFFSET 0x0086 +#define IDE0_STATUS_REG_OFFSET 0x0087 +#define IDE0_CONTROL_REG_OFFSET 0x0106 +#define IDE0_IRQ_REG_OFFSET 0x000A /* not used */ + +/* + * Definitions for IDE1 Interface + */ +#define IDE1_BASE_OFFSET 0x0C00 /* Offset in PCMCIA memory */ +#define IDE1_DATA_REG_OFFSET 0x0000 +#define IDE1_ERROR_REG_OFFSET 0x0081 +#define IDE1_NSECTOR_REG_OFFSET 0x0082 +#define IDE1_SECTOR_REG_OFFSET 0x0083 +#define IDE1_LCYL_REG_OFFSET 0x0084 +#define IDE1_HCYL_REG_OFFSET 0x0085 +#define IDE1_SELECT_REG_OFFSET 0x0086 +#define IDE1_STATUS_REG_OFFSET 0x0087 +#define IDE1_CONTROL_REG_OFFSET 0x0106 +#define IDE1_IRQ_REG_OFFSET 0x000A /* not used */ + +/* CPM Ethernet through SCCx. + * + * Bits in parallel I/O port registers that have to be set/cleared + * to configure the pins for SCC2 use. + */ +#define PA_ENET_MDC ((ushort)0x0001) /* PA 15 !!! */ +#define PA_ENET_MDIO ((ushort)0x0002) /* PA 14 !!! */ +#define PA_ENET_RXD ((ushort)0x0004) /* PA 13 */ +#define PA_ENET_TXD ((ushort)0x0008) /* PA 12 */ +#define PA_ENET_RCLK ((ushort)0x0200) /* PA 6 */ +#define PA_ENET_TCLK ((ushort)0x0400) /* PA 5 */ + +#define PB_ENET_TENA ((uint)0x00002000) /* PB 18 */ + +#define PC_ENET_CLSN ((ushort)0x0040) /* PC 9 */ +#define PC_ENET_RENA ((ushort)0x0080) /* PC 8 */ +#define PC_ENET_RESET ((ushort)0x0100) /* PC 7 !!! */ + +/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK2) to + * SCC2. Also, make sure GR2 (bit 16) and SC2 (bit 17) are zero. + */ +#define SICR_ENET_MASK ((uint)0x0000ff00) +#define SICR_ENET_CLKRT ((uint)0x00002E00) + +/* We don't use the 8259. +*/ +#define NR_8259_INTS 0 + +#endif /* !__ASSEMBLY__ */ +#endif /* __ASM_SPD8XX_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/spruce.c b/arch/ppc/platforms/spruce.c new file mode 100644 index 00000000000..5ad70d357cb --- /dev/null +++ b/arch/ppc/platforms/spruce.c @@ -0,0 +1,325 @@ +/* + * arch/ppc/platforms/spruce.c + * + * Board and PCI setup routines for IBM Spruce + * + * Author: MontaVista Software <source@mvista.com> + * + * 2000-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. + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/types.h> +#include <linux/major.h> +#include <linux/initrd.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/seq_file.h> +#include <linux/ide.h> +#include <linux/root_dev.h> +#include <linux/serial.h> +#include <linux/tty.h> +#include <linux/serial_core.h> + +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/machdep.h> +#include <asm/time.h> +#include <asm/todc.h> +#include <asm/bootinfo.h> +#include <asm/kgdb.h> + +#include <syslib/cpc700.h> + +#include "spruce.h" + +static inline int +spruce_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {23, 24, 25, 26}, /* IDSEL 1 - PCI slot 3 */ + {24, 25, 26, 23}, /* IDSEL 2 - PCI slot 2 */ + {25, 26, 23, 24}, /* IDSEL 3 - PCI slot 1 */ + {26, 23, 24, 25}, /* IDSEL 4 - PCI slot 0 */ + }; + + const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +} + +static void __init +spruce_setup_hose(void) +{ + struct pci_controller *hose; + + /* Setup hose */ + hose = pcibios_alloc_controller(); + if (!hose) + return; + + hose->first_busno = 0; + hose->last_busno = 0xff; + + pci_init_resource(&hose->io_resource, + SPRUCE_PCI_LOWER_IO, + SPRUCE_PCI_UPPER_IO, + IORESOURCE_IO, + "PCI host bridge"); + + pci_init_resource(&hose->mem_resources[0], + SPRUCE_PCI_LOWER_MEM, + SPRUCE_PCI_UPPER_MEM, + IORESOURCE_MEM, + "PCI host bridge"); + + hose->io_space.start = SPRUCE_PCI_LOWER_IO; + hose->io_space.end = SPRUCE_PCI_UPPER_IO; + hose->mem_space.start = SPRUCE_PCI_LOWER_MEM; + hose->mem_space.end = SPRUCE_PCI_UPPER_MEM; + hose->io_base_virt = (void *)SPRUCE_ISA_IO_BASE; + + setup_indirect_pci(hose, + SPRUCE_PCI_CONFIG_ADDR, + SPRUCE_PCI_CONFIG_DATA); + + hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); + + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = spruce_map_irq; +} + +/* + * CPC700 PIC interrupt programming table + * + * First entry is the sensitivity (level/edge), second is the polarity. + */ +unsigned int cpc700_irq_assigns[32][2] = { + { 1, 1 }, /* IRQ 0: ECC Correctable Error - rising edge */ + { 1, 1 }, /* IRQ 1: PCI Write Mem Range - rising edge */ + { 0, 1 }, /* IRQ 2: PCI Write Command Reg - active high */ + { 0, 1 }, /* IRQ 3: UART 0 - active high */ + { 0, 1 }, /* IRQ 4: UART 1 - active high */ + { 0, 1 }, /* IRQ 5: ICC 0 - active high */ + { 0, 1 }, /* IRQ 6: ICC 1 - active high */ + { 0, 1 }, /* IRQ 7: GPT Compare 0 - active high */ + { 0, 1 }, /* IRQ 8: GPT Compare 1 - active high */ + { 0, 1 }, /* IRQ 9: GPT Compare 2 - active high */ + { 0, 1 }, /* IRQ 10: GPT Compare 3 - active high */ + { 0, 1 }, /* IRQ 11: GPT Compare 4 - active high */ + { 0, 1 }, /* IRQ 12: GPT Capture 0 - active high */ + { 0, 1 }, /* IRQ 13: GPT Capture 1 - active high */ + { 0, 1 }, /* IRQ 14: GPT Capture 2 - active high */ + { 0, 1 }, /* IRQ 15: GPT Capture 3 - active high */ + { 0, 1 }, /* IRQ 16: GPT Capture 4 - active high */ + { 0, 0 }, /* IRQ 17: Reserved */ + { 0, 0 }, /* IRQ 18: Reserved */ + { 0, 0 }, /* IRQ 19: Reserved */ + { 0, 1 }, /* IRQ 20: FPGA EXT_IRQ0 - active high */ + { 1, 1 }, /* IRQ 21: Mouse - rising edge */ + { 1, 1 }, /* IRQ 22: Keyboard - rising edge */ + { 0, 0 }, /* IRQ 23: PCI Slot 3 - active low */ + { 0, 0 }, /* IRQ 24: PCI Slot 2 - active low */ + { 0, 0 }, /* IRQ 25: PCI Slot 1 - active low */ + { 0, 0 }, /* IRQ 26: PCI Slot 0 - active low */ +}; + +static void __init +spruce_calibrate_decr(void) +{ + int freq, divisor = 4; + + /* determine processor bus speed */ + freq = SPRUCE_BUS_SPEED; + tb_ticks_per_jiffy = freq / HZ / divisor; + tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000); +} + +static int +spruce_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "vendor\t\t: IBM\n"); + seq_printf(m, "machine\t\t: Spruce\n"); + + return 0; +} + +static void __init +spruce_early_serial_map(void) +{ + u32 uart_clk; + struct uart_port serial_req; + + if (SPRUCE_UARTCLK_IS_33M(readb(SPRUCE_FPGA_REG_A))) + uart_clk = SPRUCE_BAUD_33M * 16; + else + uart_clk = SPRUCE_BAUD_30M * 16; + + /* Setup serial port access */ + memset(&serial_req, 0, sizeof(serial_req)); + serial_req.uartclk = uart_clk; + serial_req.irq = UART0_INT; + serial_req.flags = ASYNC_BOOT_AUTOCONF; + serial_req.iotype = SERIAL_IO_MEM; + serial_req.membase = (u_char *)UART0_IO_BASE; + serial_req.regshift = 0; + +#if defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG) + gen550_init(0, &serial_req); +#endif +#ifdef CONFIG_SERIAL_8250 + if (early_serial_setup(&serial_req) != 0) + printk("Early serial init of port 0 failed\n"); +#endif + + /* Assume early_serial_setup() doesn't modify serial_req */ + serial_req.line = 1; + serial_req.irq = UART1_INT; + serial_req.membase = (u_char *)UART1_IO_BASE; + +#if defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG) + gen550_init(1, &serial_req); +#endif +#ifdef CONFIG_SERIAL_8250 + if (early_serial_setup(&serial_req) != 0) + printk("Early serial init of port 1 failed\n"); +#endif +} + +TODC_ALLOC(); + +static void __init +spruce_setup_arch(void) +{ + /* Setup TODC access */ + TODC_INIT(TODC_TYPE_DS1643, 0, 0, SPRUCE_RTC_BASE_ADDR, 8); + + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000 / HZ; + + /* Setup PCI host bridge */ + spruce_setup_hose(); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_SDA1; +#endif + + /* Identify the system */ + printk(KERN_INFO "System Identification: IBM Spruce\n"); + printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n"); +} + +static void +spruce_restart(char *cmd) +{ + local_irq_disable(); + + /* SRR0 has system reset vector, SRR1 has default MSR value */ + /* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */ + __asm__ __volatile__ + ("\n\ + lis 3,0xfff0 \n\ + ori 3,3,0x0100 \n\ + mtspr 26,3 \n\ + li 3,0 \n\ + mtspr 27,3 \n\ + rfi \n\ + "); + for(;;); +} + +static void +spruce_power_off(void) +{ + for(;;); +} + +static void +spruce_halt(void) +{ + spruce_restart(NULL); +} + +static void __init +spruce_map_io(void) +{ + io_block_mapping(SPRUCE_PCI_IO_BASE, SPRUCE_PCI_PHY_IO_BASE, + 0x08000000, _PAGE_IO); +} + +/* + * Set BAT 3 to map 0xf8000000 to end of physical memory space 1-to-1. + */ +static __inline__ void +spruce_set_bat(void) +{ + mb(); + mtspr(SPRN_DBAT1U, 0xf8000ffe); + mtspr(SPRN_DBAT1L, 0xf800002a); + mb(); +} + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + parse_bootinfo(find_bootinfo()); + + /* Map in board regs, etc. */ + spruce_set_bat(); + + isa_io_base = SPRUCE_ISA_IO_BASE; + pci_dram_offset = SPRUCE_PCI_SYS_MEM_BASE; + + ppc_md.setup_arch = spruce_setup_arch; + ppc_md.show_cpuinfo = spruce_show_cpuinfo; + ppc_md.init_IRQ = cpc700_init_IRQ; + ppc_md.get_irq = cpc700_get_irq; + + ppc_md.setup_io_mappings = spruce_map_io; + + ppc_md.restart = spruce_restart; + ppc_md.power_off = spruce_power_off; + ppc_md.halt = spruce_halt; + + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.calibrate_decr = spruce_calibrate_decr; + + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; + + spruce_early_serial_map(); + +#ifdef CONFIG_SERIAL_TEXT_DEBUG + ppc_md.progress = gen550_progress; +#endif /* CONFIG_SERIAL_TEXT_DEBUG */ +#ifdef CONFIG_KGDB + ppc_md.kgdb_map_scc = gen550_kgdb_map_scc; +#endif +} diff --git a/arch/ppc/platforms/spruce.h b/arch/ppc/platforms/spruce.h new file mode 100644 index 00000000000..a31ff7ee698 --- /dev/null +++ b/arch/ppc/platforms/spruce.h @@ -0,0 +1,71 @@ +/* + * include/asm-ppc/platforms/spruce.h + * + * Definitions for IBM Spruce reference board support + * + * Authors: Matt Porter and Johnnie Peters + * mporter@mvista.com + * jpeters@mvista.com + * + * 2001 (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. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_SPRUCE_H__ +#define __ASM_SPRUCE_H__ + +#define SPRUCE_PCI_CONFIG_ADDR 0xfec00000 +#define SPRUCE_PCI_CONFIG_DATA 0xfec00004 + +#define SPRUCE_PCI_PHY_IO_BASE 0xf8000000 +#define SPRUCE_PCI_IO_BASE SPRUCE_PCI_PHY_IO_BASE + +#define SPRUCE_PCI_SYS_MEM_BASE 0x00000000 + +#define SPRUCE_PCI_LOWER_MEM 0x80000000 +#define SPRUCE_PCI_UPPER_MEM 0x9fffffff +#define SPRUCE_PCI_LOWER_IO 0x00000000 +#define SPRUCE_PCI_UPPER_IO 0x03ffffff + +#define SPRUCE_ISA_IO_BASE SPRUCE_PCI_IO_BASE + +#define SPRUCE_MEM_SIZE 0x04000000 +#define SPRUCE_BUS_SPEED 66666667 + +#define SPRUCE_NVRAM_BASE_ADDR 0xff800000 +#define SPRUCE_RTC_BASE_ADDR SPRUCE_NVRAM_BASE_ADDR + +/* + * Serial port defines + */ +#define SPRUCE_FPGA_REG_A 0xff820000 +#define SPRUCE_UARTCLK_33M 0x02 +#define SPRUCE_UARTCLK_IS_33M(reg) (reg & SPRUCE_UARTCLK_33M) + +#define UART0_IO_BASE 0xff600300 +#define UART1_IO_BASE 0xff600400 + +#define RS_TABLE_SIZE 2 + +#define SPRUCE_BAUD_33M (33000000/64) +#define SPRUCE_BAUD_30M (30000000/64) +#define BASE_BAUD SPRUCE_BAUD_33M + +#define UART0_INT 3 +#define UART1_INT 4 + +#define STD_UART_OP(num) \ + { 0, BASE_BAUD, 0, UART##num##_INT, \ + ASYNC_BOOT_AUTOCONF, \ + iomem_base: (unsigned char *) UART##num##_IO_BASE, \ + io_type: SERIAL_IO_MEM}, + +#define SERIAL_PORT_DFNS \ + STD_UART_OP(0) \ + STD_UART_OP(1) + +#endif /* __ASM_SPRUCE_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/tqm8260.h b/arch/ppc/platforms/tqm8260.h new file mode 100644 index 00000000000..c7a78a646c6 --- /dev/null +++ b/arch/ppc/platforms/tqm8260.h @@ -0,0 +1,23 @@ +/* + * TQM8260 board specific definitions + * + * Copyright (c) 2001 Wolfgang Denk (wd@denx.de) + */ + +#ifndef __TQM8260_PLATFORM +#define __TQM8260_PLATFORM + +#include <linux/config.h> + +#include <asm/ppcboot.h> + +#define CPM_MAP_ADDR ((uint)0xFFF00000) +#define PHY_INTERRUPT 25 + +/* For our show_cpuinfo hooks. */ +#define CPUINFO_VENDOR "IN2 Systems" +#define CPUINFO_MACHINE "TQM8260 PowerPC" + +#define BOOTROM_RESTART_ADDR ((uint)0x40000104) + +#endif /* __TQM8260_PLATFORM */ diff --git a/arch/ppc/platforms/tqm8260_setup.c b/arch/ppc/platforms/tqm8260_setup.c new file mode 100644 index 00000000000..a8880bfc034 --- /dev/null +++ b/arch/ppc/platforms/tqm8260_setup.c @@ -0,0 +1,44 @@ +/* + * arch/ppc/platforms/tqm8260_setup.c + * + * TQM8260 platform support + * + * Author: Allen Curtis <acurtis@onz.com> + * Derived from: m8260_setup.c by Dan Malek, MVista + * + * Copyright 2002 Ones and Zeros, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/init.h> + +#include <asm/immap_cpm2.h> +#include <asm/mpc8260.h> +#include <asm/machdep.h> + +static int +tqm8260_set_rtc_time(unsigned long time) +{ + ((cpm2_map_t *)CPM_MAP_ADDR)->im_sit.sit_tmcnt = time; + ((cpm2_map_t *)CPM_MAP_ADDR)->im_sit.sit_tmcntsc = 0x3; + + return(0); +} + +static unsigned long +tqm8260_get_rtc_time(void) +{ + return ((cpm2_map_t *)CPM_MAP_ADDR)->im_sit.sit_tmcnt; +} + +void __init +m82xx_board_init(void) +{ + /* Anything special for this platform */ + ppc_md.set_rtc_time = tqm8260_set_rtc_time; + ppc_md.get_rtc_time = tqm8260_get_rtc_time; +} diff --git a/arch/ppc/platforms/tqm8xx.h b/arch/ppc/platforms/tqm8xx.h new file mode 100644 index 00000000000..2150dc87b18 --- /dev/null +++ b/arch/ppc/platforms/tqm8xx.h @@ -0,0 +1,179 @@ +/* + * TQM8xx(L) board specific definitions + * + * Copyright (c) 1999-2002 Wolfgang Denk (wd@denx.de) + */ + +#ifdef __KERNEL__ +#ifndef __MACH_TQM8xx_H +#define __MACH_TQM8xx_H + +#include <linux/config.h> + +#include <asm/ppcboot.h> + +#ifndef __ASSEMBLY__ +#define TQM_IMMR_BASE 0xFFF00000 /* phys. addr of IMMR */ +#define TQM_IMAP_SIZE (64 * 1024) /* size of mapped area */ + +#define IMAP_ADDR TQM_IMMR_BASE /* physical base address of IMMR area */ +#define IMAP_SIZE TQM_IMAP_SIZE /* mapped size of IMMR area */ + +/*----------------------------------------------------------------------- + * PCMCIA stuff + *----------------------------------------------------------------------- + * + */ +#define PCMCIA_MEM_SIZE ( 64 << 20 ) + +#ifndef CONFIG_KUP4K +# define MAX_HWIFS 1 /* overwrite default in include/asm-ppc/ide.h */ + +#else /* CONFIG_KUP4K */ + +# define MAX_HWIFS 2 /* overwrite default in include/asm-ppc/ide.h */ +# ifndef __ASSEMBLY__ +# include <asm/8xx_immap.h> +static __inline__ void ide_led(int on) +{ + volatile immap_t *immap = (immap_t *)IMAP_ADDR; + + if (on) { + immap->im_ioport.iop_padat &= ~0x80; + } else { + immap->im_ioport.iop_padat |= 0x80; + } +} +# endif /* __ASSEMBLY__ */ +# define IDE_LED(x) ide_led((x)) +#endif /* CONFIG_KUP4K */ + +/* + * Definitions for IDE0 Interface + */ +#define IDE0_BASE_OFFSET 0 +#define IDE0_DATA_REG_OFFSET (PCMCIA_MEM_SIZE + 0x320) +#define IDE0_ERROR_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 1) +#define IDE0_NSECTOR_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 2) +#define IDE0_SECTOR_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 3) +#define IDE0_LCYL_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 4) +#define IDE0_HCYL_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 5) +#define IDE0_SELECT_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 6) +#define IDE0_STATUS_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 7) +#define IDE0_CONTROL_REG_OFFSET 0x0106 +#define IDE0_IRQ_REG_OFFSET 0x000A /* not used */ + +/* define IO_BASE for PCMCIA */ +#define _IO_BASE 0x80000000 +#define _IO_BASE_SIZE (64<<10) + +#define FEC_INTERRUPT 9 /* = SIU_LEVEL4 */ +#define PHY_INTERRUPT 12 /* = IRQ6 */ +#define IDE0_INTERRUPT 13 + +#ifdef CONFIG_IDE +#endif + +/*----------------------------------------------------------------------- + * CPM Ethernet through SCCx. + *----------------------------------------------------------------------- + * + */ + +/*** TQM823L, TQM850L ***********************************************/ + +#if defined(CONFIG_TQM823L) || defined(CONFIG_TQM850L) +/* Bits in parallel I/O port registers that have to be set/cleared + * to configure the pins for SCC1 use. + */ +#define PA_ENET_RXD ((ushort)0x0004) /* PA 13 */ +#define PA_ENET_TXD ((ushort)0x0008) /* PA 12 */ +#define PA_ENET_RCLK ((ushort)0x0100) /* PA 7 */ +#define PA_ENET_TCLK ((ushort)0x0400) /* PA 5 */ + +#define PB_ENET_TENA ((uint)0x00002000) /* PB 18 */ + +#define PC_ENET_CLSN ((ushort)0x0040) /* PC 9 */ +#define PC_ENET_RENA ((ushort)0x0080) /* PC 8 */ + +/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK1) to + * SCC2. Also, make sure GR2 (bit 16) and SC2 (bit 17) are zero. + */ +#define SICR_ENET_MASK ((uint)0x0000ff00) +#define SICR_ENET_CLKRT ((uint)0x00002600) +#endif /* CONFIG_TQM823L, CONFIG_TQM850L */ + +/*** TQM860L ********************************************************/ + +#ifdef CONFIG_TQM860L +/* Bits in parallel I/O port registers that have to be set/cleared + * to configure the pins for SCC1 use. + */ +#define PA_ENET_RXD ((ushort)0x0001) /* PA 15 */ +#define PA_ENET_TXD ((ushort)0x0002) /* PA 14 */ +#define PA_ENET_RCLK ((ushort)0x0100) /* PA 7 */ +#define PA_ENET_TCLK ((ushort)0x0400) /* PA 5 */ + +#define PC_ENET_TENA ((ushort)0x0001) /* PC 15 */ +#define PC_ENET_CLSN ((ushort)0x0010) /* PC 11 */ +#define PC_ENET_RENA ((ushort)0x0020) /* PC 10 */ + +/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK1) to + * SCC1. Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero. + */ +#define SICR_ENET_MASK ((uint)0x000000ff) +#define SICR_ENET_CLKRT ((uint)0x00000026) +#endif /* CONFIG_TQM860L */ + +/*** FPS850L *********************************************************/ + +#ifdef CONFIG_FPS850L +/* Bits in parallel I/O port registers that have to be set/cleared + * to configure the pins for SCC1 use. + */ +#define PA_ENET_RXD ((ushort)0x0004) /* PA 13 */ +#define PA_ENET_TXD ((ushort)0x0008) /* PA 12 */ +#define PA_ENET_RCLK ((ushort)0x0100) /* PA 7 */ +#define PA_ENET_TCLK ((ushort)0x0400) /* PA 5 */ + +#define PC_ENET_TENA ((ushort)0x0002) /* PC 14 */ +#define PC_ENET_CLSN ((ushort)0x0040) /* PC 9 */ +#define PC_ENET_RENA ((ushort)0x0080) /* PC 8 */ + +/* Control bits in the SICR to route TCLK (CLK2) and RCLK (CLK4) to + * SCC2. Also, make sure GR2 (bit 16) and SC2 (bit 17) are zero. + */ +#define SICR_ENET_MASK ((uint)0x0000ff00) +#define SICR_ENET_CLKRT ((uint)0x00002600) +#endif /* CONFIG_FPS850L */ + +/*** SM850 *********************************************************/ + +/* The SM850 Service Module uses SCC2 for IrDA and SCC3 for Ethernet */ + +#ifdef CONFIG_SM850 +#define PB_ENET_RXD ((uint)0x00000004) /* PB 29 */ +#define PB_ENET_TXD ((uint)0x00000002) /* PB 30 */ +#define PA_ENET_RCLK ((ushort)0x0100) /* PA 7 */ +#define PA_ENET_TCLK ((ushort)0x0400) /* PA 5 */ + +#define PC_ENET_LBK ((ushort)0x0008) /* PC 12 */ +#define PC_ENET_TENA ((ushort)0x0004) /* PC 13 */ + +#define PC_ENET_RENA ((ushort)0x0800) /* PC 4 */ +#define PC_ENET_CLSN ((ushort)0x0400) /* PC 5 */ + +/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK1) to + * SCC3. Also, make sure GR3 (bit 8) and SC3 (bit 9) are zero. + */ +#define SICR_ENET_MASK ((uint)0x00FF0000) +#define SICR_ENET_CLKRT ((uint)0x00260000) +#endif /* CONFIG_SM850 */ + +/* We don't use the 8259. +*/ +#define NR_8259_INTS 0 + +#endif /* !__ASSEMBLY__ */ +#endif /* __MACH_TQM8xx_H */ +#endif /* __KERNEL__ */ |