MV64360 ethernet controller

Dale Farnsworth dale at farnsworth.org
Thu Feb 1 23:13:52 EST 2007


sb at thebackend.de wrote:
> I recently got a few Force/Motorola PowerPMC-280 PMC modules  
> consisting mainly of a MPC7447 G4 an the Marvell MV64360 system  
> controller. Since this a hobbyist project only I don't have  
> Montavista Linux which seems to already support the board. Instead I  
> ported the stock Linux kernel. Works quite well so far. The only  
> thing I did not get to work is the integrated ethernet. The  
> mv64360_eth driver loads fine and sees both ports. It does not get  
> any interrupts for incoming packets (activity led blinks though).  
> Only unplugging the cable generates an interrupt.
> 
> Since I do not have any documentation on the Marvell chip and the  
> company does not answer my request I am quite lost.
> 
> The PHY interrupts are routed to one of the GPIO/interrupt pins. I  
> did not find any code in the ethernet driver that would be able to  
> use it though. Is it needed at all?
> 
> Any hint is appreciated!
> Sebastian

Hi Sebastian,

Yes, the driver needs receive and transmit interrupts.  However, the
same irq number is used for PHY status change as well as for packet
receive and transmit.  I don't see how you could see PHY status change
interrupts and not rx/tx interrupts.  mv643xx_eth_int_handler() should
be called for all ethernet-related interrupts*.  Are you certain that
you're not seeing rx and tx interrupts?

* You may not see an interrupt on every packet because of the
transmit irq coalescing mechanism and the use of NAPI on receive.

Mark Greer and I are starting on arch/powerpc support for the mv64x60
and ppmc280.  We will submit it as when we have something useful.
In the meantime, the arch/ppc code below may serve as a hint.
(Just to be clear, I didn't write this code and don't mean to take
credit for it.)

-Dale

/*
 * arch/ppc/platforms/ppmc280.h
 *
 * Definitions for Motorola  PPMC280 board
 *
 * Based on db64360.h, Written by Rabeeh Khoury - rabeeh at galileo.co.il
 * Based on code done by Mark A. Greer <mgreer at 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):
 *
 *     0xf2040000-0xffffffff           - Unused
 *     0xf2000000-0xf203ffff           - Integrated SRAM
 *     0xf1010000-0xf1ffffff           - Unused
 *     0xf1000000-0xf100ffff           - MV64360 Registers
 *     0xc0800000-0xf0ffffff           - Unused
 *     0xc0000000-0xc07fffff           - Boot flash (BootCS#)
 *     0xb2000000-0xb2ffffff           - User flash 1 ( CS1)
 *     0xb0000000-0xb1ffffff           - User flash 0 ( CS0)
 *     0xa8000000-0x9fffffff           - Unused
 *     0xa8000000-0xa7ffffff           - PCI 1 I/O (defined in mv64360.h)
 *     0xa0000000-0xa7ffffff           - PCI 0 I/O (defined in mv64360.h)
 *     0x90000000-0x9fffffff           - PCI 1 MEM (defined in mv64360.h)
 *     0x80000000-0x8fffffff           - PCI 0 MEM (defined in mv64360.h)
 *     0x20000000-0x7fffffff           - Reserved for SDRAM expansion
 *     0x00000000-0x1fffffff           - On Board SDRAM ( CS0)
 */

#ifndef __PPC_PLATFORMS_PPMC280
#define __PPC_PLATFORMS_PPMC280

/* PCI mappings */
#define PPMC280_PCI0_IO_CPU_BASE        0xa0000000
#define PPMC280_PCI0_IO_PCI_BASE        0x00000000
#define PPMC280_PCI0_IO_SIZE            0x01000000

#define PPMC280_PCI0_MEM_CPU_BASE       0x80000000
#define PPMC280_PCI0_MEM_PCI_BASE       0x80000000
#define PPMC280_PCI0_MEM_SIZE           0x10000000

#define PPMC280_PCI1_IO_CPU_BASE        (PPMC280_PCI0_IO_CPU_BASE + \
                                                PPMC280_PCI0_IO_SIZE)
#define PPMC280_PCI1_IO_PCI_BASE        (PPMC280_PCI0_IO_PCI_BASE + \
                                                PPMC280_PCI0_IO_SIZE)
#define PPMC280_PCI1_IO_SIZE            0x01000000

#define PPMC280_PCI1_MEM_CPU_BASE       (PPMC280_PCI0_MEM_CPU_BASE + \
                                                PPMC280_PCI0_MEM_SIZE)
#define PPMC280_PCI1_MEM_PCI_BASE       (PPMC280_PCI0_MEM_PCI_BASE + \
                                                PPMC280_PCI0_MEM_SIZE)
#define PPMC280_PCI1_MEM_SIZE           0x10000000

/* CPU Physical Memory Map setup (other than PCI) */
#define PPMC280_EXT_FLASH_BASE_1	0xb0000000
#define PPMC280_EXT_FLASH_BASE_2	0xb2000000
#define PPMC280_BOOT_FLASH_BASE		0xc0000000  /* BOOT FLASH Base */
#define PPMC280_INTERNAL_SRAM_BASE      0xf2000000

#if defined(CONFIG_MTD_PPMC2800D_FLASH) || defined(CONFIG_MTD_PPMC2800D_FLASH_MODULE)
#define PPMC280_EXT_FLASH_SIZE_ACTUAL	0x04000000
#define PPMC280_BOOT_FLASH_SIZE_ACTUAL	0x01000000  /* =< 16M of Boot FLASH */
#else
#define PPMC280_EXT_FLASH_SIZE_ACTUAL	0x02000000
#define PPMC280_BOOT_FLASH_SIZE_ACTUAL	0x00800000  /* =< 8M of Boot FLASH */
#endif
#define	PPMC280_INTERNAL_SRAM_SIZE	0x00040000

#define	PPMC280_EXT_FLASH_SIZE		max(MV64360_WINDOW_SIZE_MIN,	\
						PPMC280_EXT_FLASH_SIZE_ACTUAL)
#define	PPMC280_BOOT_FLASH_SIZE		max(MV64360_WINDOW_SIZE_MIN, \
						PPMC280_BOOT_FLASH_SIZE_ACTUAL)
#define	PPMC280_EXT_SRAM_SIZE		max(MV64360_WINDOW_SIZE_MIN,	\
						PPMC280_EXT_SRAM_SIZE_ACTUAL)

/* Board-specific IRQ info */
#define PPMC280_PCI_0_IRQ_A             64+27
#define PPMC280_PCI_0_IRQ_B             64+29
#define PPMC280_PCI_0_IRQ_C             64+16
#define PPMC280_PCI_0_IRQ_D             64+17


/* Serial port setup */
#define	PPMC280_DEFAULT_BAUD		9600

#if defined(CONFIG_SERIAL_MPSC_CONSOLE)
#define	PPMC280_MPSC_CLK_SRC		8		/* TCLK */
#define	PPMC280_MPSC_CLK_FREQ		133000000
#endif
#endif /* __PPC_PLATFORMS_PPMC280 */

/*
 * arch/ppc/platforms/ppmc280.c
 *
 * Board setup routines for the Motorola PPMC280 Development Board.
 *
 * Author: <source at mvista.com>
 * Based on ppmc280.c Written by Rabeeh Khoury - rabeeh at galileo.co.il
 * Based on code done by - Mark A. Greer <mgreer at 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.
 */

#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/mv64x60.h>
#include <asm/time.h>
#include <platforms/ppmc280.h>

#define BOARD_VENDOR	"Motorola"
#define BOARD_MACHINE	"PPMC280"

static struct mv64x60_handle bh;

static const unsigned int cpu_7447[32] = {
	23, 34, 15, 30, 14, 36, 1, 40, 4, 42, 13, 26, 17, 48, 19, 18,
	 6, 21, 11, 22, 8, 20, 10, 24, 16, 28, 12, 32, 27, 56, 0, 25
};

static int ppmc280_get_bus_speed(void)
{
	return 133333333;
}
static int ppmc280_get_cpu_speed(void)
{
	unsigned long hid1;

	hid1 = (mfspr(SPRN_HID1) & 0x0001f000) >> 12;
	return ppmc280_get_bus_speed() * cpu_7447[hid1] / 2;
}

unsigned long __init ppmc280_find_end_of_memory(void)
{
	return mv64x60_get_mem_size(CONFIG_MV64X60_NEW_BASE,
			MV64x60_TYPE_MV64360);
}

/*
 * Motorola PPMC280 Board PCI interrupt routing.
 */
static int __init
ppmc280_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
		 */
		/* IDSEL 10 - PCI bus 0 */
		{ PPMC280_PCI_0_IRQ_C, PPMC280_PCI_0_IRQ_D,
		  PPMC280_PCI_0_IRQ_A, PPMC280_PCI_0_IRQ_B },
		/* IDSEL 11 - PCI bus 0 */
		{ PPMC280_PCI_0_IRQ_A, PPMC280_PCI_0_IRQ_B,
		  PPMC280_PCI_0_IRQ_C, PPMC280_PCI_0_IRQ_D },
		/* IDSEL 12 - PCI bus 0 */
		{ PPMC280_PCI_0_IRQ_A, PPMC280_PCI_0_IRQ_B,
		  PPMC280_PCI_0_IRQ_C, PPMC280_PCI_0_IRQ_D },
		/* IDSEL 13 - PCI bus 0 */
		{ PPMC280_PCI_0_IRQ_B, PPMC280_PCI_0_IRQ_C,
		  PPMC280_PCI_0_IRQ_D, PPMC280_PCI_0_IRQ_A },
	};
	const long min_idsel = 10, max_idsel = 13, irqs_per_slot = 4;
	return PCI_IRQ_TABLE_LOOKUP;
}

static void __init
ppmc280_setup_peripherals(void)
{

	u32 temp;

	mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN,
		PPMC280_BOOT_FLASH_BASE, PPMC280_BOOT_FLASH_SIZE, 0);
	bh.ci->enable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN);

	mv64x60_set_32bit_window(&bh, MV64x60_CPU2SRAM_WIN,
		PPMC280_INTERNAL_SRAM_BASE, PPMC280_INTERNAL_SRAM_SIZE, 0);
	bh.ci->enable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN);

	mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_0_WIN,
		PPMC280_EXT_FLASH_BASE_1, PPMC280_EXT_FLASH_SIZE, 0);
	bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_0_WIN);

	mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN,
		PPMC280_EXT_FLASH_BASE_2, PPMC280_EXT_FLASH_SIZE, 0);
	bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_1_WIN);

	mv64x60_clr_bits(&bh, MV64x60_CPU_CONFIG,
		((1 << 12) | (1 << 28) | (1 << 29)));
	mv64x60_set_bits(&bh, MV64x60_CPU_CONFIG, (1 << 27));

	if (ppmc280_get_bus_speed() > 100000000)
		mv64x60_set_bits(&bh, MV64x60_CPU_CONFIG, (1 << 23));

	mv64x60_set_bits(&bh, MV64x60_CPU_MASTER_CNTL, (1 << 9)); /* 1 cpu */

	/* Program WatchDog o/p MPP19:WDE# i.e. 0x4, MPP24:WDNMI# i.e. 0x4 */
	temp = mv64x60_read(&bh, MV64x60_MPP_CNTL_2);
	temp &= 0xFFFF0FFF;
	temp |= 0x00004000;
	mv64x60_write(&bh, MV64x60_MPP_CNTL_2, temp);

	temp = mv64x60_read(&bh, MV64x60_MPP_CNTL_3);
	temp &= 0xFFFFFFF0;
	temp |= 0x00000004;
	mv64x60_write(&bh, MV64x60_MPP_CNTL_3, temp);

	/* Make sure WatchDog is disabled */
	temp = mv64x60_read(&bh, MV64x60_WDT_WDC);
	if (temp & 0x80000000) {	/* Is the WD enabled ? */
		temp &= ~0x3000000;
		temp |= 0x1000000;
		mv64x60_write(&bh, MV64x60_WDT_WDC, temp);
		temp &= ~0x3000000;
		temp |= 0x2000000;
		mv64x60_write(&bh, MV64x60_WDT_WDC, temp);
	}

	/*
	 * 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_set_bits(&bh, MV64x60_GPP_LEVEL_CNTL, 0xfb50);
	mv64x60_set_bits(&bh, MV64x60_GPP_IO_CNTL, 0xfb50);

#if defined(CONFIG_NOT_COHERENT_CACHE)
	mv64x60_write(&bh, MV64360_SRAM_CONFIG, 0x00160000);
#else
	mv64x60_write(&bh, MV64360_SRAM_CONFIG, 0x001600b2);
#endif
	return;
}

static void __init
ppmc280_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 = PPMC280_PCI0_IO_CPU_BASE;
	si.pci_0.pci_io.pci_base_hi = 0;
	si.pci_0.pci_io.pci_base_lo = PPMC280_PCI0_IO_PCI_BASE;
	si.pci_0.pci_io.size = PPMC280_PCI0_IO_SIZE;
	si.pci_0.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE;
	si.pci_0.pci_mem[0].cpu_base = PPMC280_PCI0_MEM_CPU_BASE;
	si.pci_0.pci_mem[0].pci_base_hi = 0;
	si.pci_0.pci_mem[0].pci_base_lo = PPMC280_PCI0_MEM_PCI_BASE;
	si.pci_0.pci_mem[0].size = PPMC280_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;

	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;
#else
		si.cpu_prot_options[i] = 0;
		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;
#endif
	}

	if (ppc_md.progress)
		ppc_md.progress("ppmc280_setup_bridge: mv64x60_init", 0);

	/* 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 = ppmc280_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);

	if (ppc_md.progress)
		ppc_md.progress("ppmc280_setup_bridge: return", 0);
	return;
}

static void __init
ppmc280_setup_arch(void)
{
	if (ppc_md.progress)
		ppc_md.progress("ppmc280_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("ppmc280_setup_arch: Enabling L2 cache", 0);

	/* Enable L2 cache but not L3 cache (if 744x/745x) */
	_set_L2CR(_get_L2CR() | L2CR_L2E);

	if (ppc_md.progress)
		ppc_md.progress("ppmc280_setup_arch: Initializing bridge", 0);

	ppmc280_setup_bridge();	/* set up PCI bridge(s) */
	ppmc280_setup_peripherals();	/* set up chip selects/GPP/MPP etc */

	if (ppc_md.progress)
		ppc_md.progress("ppmc280_setup_arch: bridge init complete", 0);

	printk(KERN_INFO "%s %s port (C) 2001 MontaVista Software, Inc."
		"(source at mvista.com)\n", BOARD_VENDOR, BOARD_MACHINE);

	if (ppc_md.progress)
		ppc_md.progress("ppmc280_setup_arch: exit", 0);

	return;
}

/* Platform device data fixup routines. */
#if defined(CONFIG_SERIAL_MPSC)
static void __init
ppmc280_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 = PPMC280_DEFAULT_BAUD;
	pdata->brg_clk_src = PPMC280_MPSC_CLK_SRC;
	pdata->brg_clk_freq = PPMC280_MPSC_CLK_FREQ;

	return;
}
static int
ppmc280_platform_notify(struct device *dev)
{
	static struct {
		char *bus_id;
		void ((*rtn) (struct platform_device * pdev));
	} dev_map[] = {
		{ MPSC_CTLR_NAME ".0", ppmc280_fixup_mpsc_pdata },
		{ MPSC_CTLR_NAME ".1", ppmc280_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
ppmc280_reset_board(void *addr)
{
	u32 temp;

	local_irq_disable();

	temp = mv64x60_read(&bh, MV64x60_MPP_CNTL_0);
	temp &= 0xFFFF0FFF;
	mv64x60_write(&bh, MV64x60_MPP_CNTL_0, temp);

	mv64x60_set_bits(&bh, MV64x60_GPP_LEVEL_CNTL, 0x0004);
	mv64x60_set_bits(&bh, MV64x60_GPP_IO_CNTL, 0x0004);

	temp = mv64x60_read(&bh, MV64x60_MPP_CNTL_2);
	temp &= 0xFFFF0FFF;
	mv64x60_write(&bh, MV64x60_MPP_CNTL_2, temp);

	mv64x60_set_bits(&bh, MV64x60_GPP_LEVEL_CNTL, 0x80000);
	mv64x60_set_bits(&bh, MV64x60_GPP_IO_CNTL, 0x80000);

	mv64x60_write(&bh, MV64x60_GPP_VALUE_SET, 0x80004);
	return;
}

static void
ppmc280_restart(char *cmd)
{
	volatile ulong i = 10000000;

	ppmc280_reset_board((void *)0xfff00100);

	while (i-- > 0);
	panic("restart failed\n");
}

static void
ppmc280_halt(void)
{
	local_irq_disable();
	while (1);
	/* NOTREACHED */
}

static void
ppmc280_power_off(void)
{
	ppmc280_halt();
	/* NOTREACHED */
}

static int
ppmc280_show_cpuinfo(struct seq_file *m)
{
	char *s;

	seq_printf(m, "cpu freq\t: %dMHz\n",
		(ppmc280_get_cpu_speed() + 500000) / 1000000);
	seq_printf(m, "bus freq\t: %dMHz\n",
		(ppmc280_get_bus_speed() + 500000) / 1000000);
	seq_printf(m, "vendor\t\t: " BOARD_VENDOR "\n");
	seq_printf(m, "machine\t\t: " BOARD_MACHINE "\n");

	switch (bh.type) {
	case MV64x60_TYPE_GT64260A:
		s = "gt64260a";
		break;
	case MV64x60_TYPE_GT64260B:
		s = "gt64260b";
		break;
	case MV64x60_TYPE_MV64360:
		s = "mv64360";
		break;
	case MV64x60_TYPE_MV64460:
		s = "mv64460";
		break;
	default:
		s = "Unknown";
	}
	seq_printf(m, "bridge type\t: %s\n", s);
	seq_printf(m, "bridge rev\t: 0x%x\n", bh.rev);
#if defined(CONFIG_NOT_COHERENT_CACHE)
	seq_printf(m, "coherency\t: %s\n", "off");
#else
	seq_printf(m, "coherency\t: %s\n", "on");
#endif

	return 0;
}

static void __init
ppmc280_calibrate_decr(void)
{
	ulong freq;

	freq = ppmc280_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;
}

#if defined(CONFIG_I2C_MV64XXX) && defined(CONFIG_SENSORS_MAX6900)
extern ulong max6900_get_rtc_time(void);
extern int max6900_set_rtc_time(ulong);

static int __init
ppmc280_rtc_hookup(void)
{
	struct timespec tv;

	if (ppc_md.progress)
		ppc_md.progress("ppmc280_rtc_hookup: ", 0);

	ppc_md.get_rtc_time = max6900_get_rtc_time;
	ppc_md.set_rtc_time = max6900_set_rtc_time;

	tv.tv_nsec = 0;
	if (ppc_md.progress)
		ppc_md.progress("ppmc280_rtc_hookup: call ppc_md.get_rtc_time",
				0);
	tv.tv_sec = (ppc_md.get_rtc_time)();
	do_settimeofday(&tv);

	return 0;
}

late_initcall(ppmc280_rtc_hookup);
#endif

/*
 * Set BAT 3 to map 0xf1000000 to end of physical memory space.
 */
static __inline__ void
ppmc280_set_bat(void)
{
	mb();
	mtspr(SPRN_DBAT1U, 0xf0001ffe);
	mtspr(SPRN_DBAT1L, 0xf000002a);
	mb();

	return;
}

#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
static void __init
ppmc280_map_io(void)
{
	io_block_mapping(0xf1000000, 0xf1000000, 0x00100000, _PAGE_IO);
	io_block_mapping(0xff800000, 0xff800000, 0x00800000, _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 = PPMC280_PCI0_IO_CPU_BASE;
	pci_dram_offset = PPMC280_PCI0_MEM_CPU_BASE;

	loops_per_jiffy = ppmc280_get_cpu_speed() / HZ;

	ppc_md.setup_arch = ppmc280_setup_arch;
	ppc_md.show_cpuinfo = ppmc280_show_cpuinfo;
	ppc_md.init_IRQ = mv64360_init_irq;
	ppc_md.get_irq = mv64360_get_irq;
	ppc_md.restart = ppmc280_restart;
	ppc_md.power_off = ppmc280_power_off;
	ppc_md.halt = ppmc280_halt;
	ppc_md.find_end_of_memory = ppmc280_find_end_of_memory;
	ppc_md.init = NULL;
	ppc_md.calibrate_decr = ppmc280_calibrate_decr;

	bh.p_base = CONFIG_MV64X60_NEW_BASE;

	ppmc280_set_bat();

#ifdef	CONFIG_SERIAL_TEXT_DEBUG
	ppc_md.setup_io_mappings = ppmc280_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 = ppmc280_map_io;
#endif				/* CONFIG_KGDB */

#if defined(CONFIG_SERIAL_MPSC)
	platform_notify = ppmc280_platform_notify;
#endif

	return;
}



More information about the Linuxppc-embedded mailing list