1
linux/arch/ppc/platforms/4xx/ebony.c
Eugene Surovegin 5ce17b18e1 [PATCH] ppc32: fix 44x early serial debug for configurations with more than 512M of RAM
Fix 44x early serial debugging for big RAM configurations (more than 512M).
 We cannot use default OpenBIOS virtual mapping, because it interferes with
pinned TLB entry.

While we are at it, move early UART mapping to TLB slot 0, so it can
survive longer during boot process (slot 1 is used by the first ioremap
call, effectively killing UART mapping if it occupies this slot).  Also,
change UART TLB entry size to 4K (256M is too much for a bunch of registers
:).  Squash some warnings on the way.

Tested on Ebony and Ocotea with 1G of RAM.

Thanks to Scott Coulter <scott.coulter@cyclone.com> for diagnosing this
problem.

Signed-off-by: Eugene Surovegin <ebs@ebshome.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-07-30 10:14:46 -07:00

360 lines
9.1 KiB
C

/*
* 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-2005 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 <asm/tlbflush.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 __iomem *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;
hose->io_base_virt = ioremap64(EBONY_PCI_IO_BASE, EBONY_PCI_IO_SIZE);
isa_io_base = (unsigned long)hose->io_base_virt;
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);
/* Purge TLB entry added in head_44x.S for early serial access */
_tlbie(UART0_IO_BASE);
#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
}