162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * TX4938/4937 setup routines
362306a36Sopenharmony_ci * Based on linux/arch/mips/txx9/rbtx4938/setup.c,
462306a36Sopenharmony_ci *	    and RBTX49xx patch from CELF patch archive.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * 2003-2005 (c) MontaVista Software, Inc.
762306a36Sopenharmony_ci * (C) Copyright TOSHIBA CORPORATION 2000-2001, 2004-2007
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
1062306a36Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
1162306a36Sopenharmony_ci * for more details.
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci#include <linux/init.h>
1462306a36Sopenharmony_ci#include <linux/ioport.h>
1562306a36Sopenharmony_ci#include <linux/delay.h>
1662306a36Sopenharmony_ci#include <linux/param.h>
1762306a36Sopenharmony_ci#include <linux/ptrace.h>
1862306a36Sopenharmony_ci#include <linux/mtd/physmap.h>
1962306a36Sopenharmony_ci#include <linux/platform_device.h>
2062306a36Sopenharmony_ci#include <linux/platform_data/txx9/ndfmc.h>
2162306a36Sopenharmony_ci#include <asm/reboot.h>
2262306a36Sopenharmony_ci#include <asm/traps.h>
2362306a36Sopenharmony_ci#include <asm/txx9irq.h>
2462306a36Sopenharmony_ci#include <asm/txx9tmr.h>
2562306a36Sopenharmony_ci#include <asm/txx9pio.h>
2662306a36Sopenharmony_ci#include <asm/txx9/generic.h>
2762306a36Sopenharmony_ci#include <asm/txx9/dmac.h>
2862306a36Sopenharmony_ci#include <asm/txx9/tx4938.h>
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic void __init tx4938_wdr_init(void)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	/* report watchdog reset status */
3362306a36Sopenharmony_ci	if (____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_WDRST)
3462306a36Sopenharmony_ci		pr_warn("Watchdog reset detected at 0x%lx\n",
3562306a36Sopenharmony_ci			read_c0_errorepc());
3662306a36Sopenharmony_ci	/* clear WatchDogReset (W1C) */
3762306a36Sopenharmony_ci	tx4938_ccfg_set(TX4938_CCFG_WDRST);
3862306a36Sopenharmony_ci	/* do reset on watchdog */
3962306a36Sopenharmony_ci	tx4938_ccfg_set(TX4938_CCFG_WR);
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_civoid __init tx4938_wdt_init(void)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	txx9_wdt_init(TX4938_TMR_REG(2) & 0xfffffffffULL);
4562306a36Sopenharmony_ci}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic void tx4938_machine_restart(char *command)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	local_irq_disable();
5062306a36Sopenharmony_ci	pr_emerg("Rebooting (with %s watchdog reset)...\n",
5162306a36Sopenharmony_ci		 (____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_WDREXEN) ?
5262306a36Sopenharmony_ci		 "external" : "internal");
5362306a36Sopenharmony_ci	/* clear watchdog status */
5462306a36Sopenharmony_ci	tx4938_ccfg_set(TX4938_CCFG_WDRST);	/* W1C */
5562306a36Sopenharmony_ci	txx9_wdt_now(TX4938_TMR_REG(2) & 0xfffffffffULL);
5662306a36Sopenharmony_ci	while (!(____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_WDRST))
5762306a36Sopenharmony_ci		;
5862306a36Sopenharmony_ci	mdelay(10);
5962306a36Sopenharmony_ci	if (____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_WDREXEN) {
6062306a36Sopenharmony_ci		pr_emerg("Rebooting (with internal watchdog reset)...\n");
6162306a36Sopenharmony_ci		/* External WDRST failed.  Do internal watchdog reset */
6262306a36Sopenharmony_ci		tx4938_ccfg_clear(TX4938_CCFG_WDREXEN);
6362306a36Sopenharmony_ci	}
6462306a36Sopenharmony_ci	/* fallback */
6562306a36Sopenharmony_ci	(*_machine_halt)();
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_civoid show_registers(struct pt_regs *regs);
6962306a36Sopenharmony_cistatic int tx4938_be_handler(struct pt_regs *regs, int is_fixup)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	int data = regs->cp0_cause & 4;
7262306a36Sopenharmony_ci	console_verbose();
7362306a36Sopenharmony_ci	pr_err("%cBE exception at %#lx\n", data ? 'D' : 'I', regs->cp0_epc);
7462306a36Sopenharmony_ci	pr_err("ccfg:%llx, toea:%llx\n",
7562306a36Sopenharmony_ci	       (unsigned long long)____raw_readq(&tx4938_ccfgptr->ccfg),
7662306a36Sopenharmony_ci	       (unsigned long long)____raw_readq(&tx4938_ccfgptr->toea));
7762306a36Sopenharmony_ci#ifdef CONFIG_PCI
7862306a36Sopenharmony_ci	tx4927_report_pcic_status();
7962306a36Sopenharmony_ci#endif
8062306a36Sopenharmony_ci	show_registers(regs);
8162306a36Sopenharmony_ci	panic("BusError!");
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_cistatic void __init tx4938_be_init(void)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	mips_set_be_handler(tx4938_be_handler);
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic struct resource tx4938_sdram_resource[4];
8962306a36Sopenharmony_cistatic struct resource tx4938_sram_resource;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci#define TX4938_SRAM_SIZE 0x800
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_civoid __init tx4938_setup(void)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	int i;
9662306a36Sopenharmony_ci	__u32 divmode;
9762306a36Sopenharmony_ci	unsigned int cpuclk = 0;
9862306a36Sopenharmony_ci	u64 ccfg;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	txx9_reg_res_init(TX4938_REV_PCODE(), TX4938_REG_BASE,
10162306a36Sopenharmony_ci			  TX4938_REG_SIZE);
10262306a36Sopenharmony_ci	set_c0_config(TX49_CONF_CWFON);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	/* SDRAMC,EBUSC are configured by PROM */
10562306a36Sopenharmony_ci	for (i = 0; i < 8; i++) {
10662306a36Sopenharmony_ci		if (!(TX4938_EBUSC_CR(i) & 0x8))
10762306a36Sopenharmony_ci			continue;	/* disabled */
10862306a36Sopenharmony_ci		txx9_ce_res[i].start = (unsigned long)TX4938_EBUSC_BA(i);
10962306a36Sopenharmony_ci		txx9_ce_res[i].end =
11062306a36Sopenharmony_ci			txx9_ce_res[i].start + TX4938_EBUSC_SIZE(i) - 1;
11162306a36Sopenharmony_ci		request_resource(&iomem_resource, &txx9_ce_res[i]);
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	/* clocks */
11562306a36Sopenharmony_ci	ccfg = ____raw_readq(&tx4938_ccfgptr->ccfg);
11662306a36Sopenharmony_ci	if (txx9_master_clock) {
11762306a36Sopenharmony_ci		/* calculate gbus_clock and cpu_clock from master_clock */
11862306a36Sopenharmony_ci		divmode = (__u32)ccfg & TX4938_CCFG_DIVMODE_MASK;
11962306a36Sopenharmony_ci		switch (divmode) {
12062306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_8:
12162306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_10:
12262306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_12:
12362306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_16:
12462306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_18:
12562306a36Sopenharmony_ci			txx9_gbus_clock = txx9_master_clock * 4; break;
12662306a36Sopenharmony_ci		default:
12762306a36Sopenharmony_ci			txx9_gbus_clock = txx9_master_clock;
12862306a36Sopenharmony_ci		}
12962306a36Sopenharmony_ci		switch (divmode) {
13062306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_2:
13162306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_8:
13262306a36Sopenharmony_ci			cpuclk = txx9_gbus_clock * 2; break;
13362306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_2_5:
13462306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_10:
13562306a36Sopenharmony_ci			cpuclk = txx9_gbus_clock * 5 / 2; break;
13662306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_3:
13762306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_12:
13862306a36Sopenharmony_ci			cpuclk = txx9_gbus_clock * 3; break;
13962306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_4:
14062306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_16:
14162306a36Sopenharmony_ci			cpuclk = txx9_gbus_clock * 4; break;
14262306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_4_5:
14362306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_18:
14462306a36Sopenharmony_ci			cpuclk = txx9_gbus_clock * 9 / 2; break;
14562306a36Sopenharmony_ci		}
14662306a36Sopenharmony_ci		txx9_cpu_clock = cpuclk;
14762306a36Sopenharmony_ci	} else {
14862306a36Sopenharmony_ci		if (txx9_cpu_clock == 0)
14962306a36Sopenharmony_ci			txx9_cpu_clock = 300000000;	/* 300MHz */
15062306a36Sopenharmony_ci		/* calculate gbus_clock and master_clock from cpu_clock */
15162306a36Sopenharmony_ci		cpuclk = txx9_cpu_clock;
15262306a36Sopenharmony_ci		divmode = (__u32)ccfg & TX4938_CCFG_DIVMODE_MASK;
15362306a36Sopenharmony_ci		switch (divmode) {
15462306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_2:
15562306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_8:
15662306a36Sopenharmony_ci			txx9_gbus_clock = cpuclk / 2; break;
15762306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_2_5:
15862306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_10:
15962306a36Sopenharmony_ci			txx9_gbus_clock = cpuclk * 2 / 5; break;
16062306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_3:
16162306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_12:
16262306a36Sopenharmony_ci			txx9_gbus_clock = cpuclk / 3; break;
16362306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_4:
16462306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_16:
16562306a36Sopenharmony_ci			txx9_gbus_clock = cpuclk / 4; break;
16662306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_4_5:
16762306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_18:
16862306a36Sopenharmony_ci			txx9_gbus_clock = cpuclk * 2 / 9; break;
16962306a36Sopenharmony_ci		}
17062306a36Sopenharmony_ci		switch (divmode) {
17162306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_8:
17262306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_10:
17362306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_12:
17462306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_16:
17562306a36Sopenharmony_ci		case TX4938_CCFG_DIVMODE_18:
17662306a36Sopenharmony_ci			txx9_master_clock = txx9_gbus_clock / 4; break;
17762306a36Sopenharmony_ci		default:
17862306a36Sopenharmony_ci			txx9_master_clock = txx9_gbus_clock;
17962306a36Sopenharmony_ci		}
18062306a36Sopenharmony_ci	}
18162306a36Sopenharmony_ci	/* change default value to udelay/mdelay take reasonable time */
18262306a36Sopenharmony_ci	loops_per_jiffy = txx9_cpu_clock / HZ / 2;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	/* CCFG */
18562306a36Sopenharmony_ci	tx4938_wdr_init();
18662306a36Sopenharmony_ci	/* clear BusErrorOnWrite flag (W1C) */
18762306a36Sopenharmony_ci	tx4938_ccfg_set(TX4938_CCFG_BEOW);
18862306a36Sopenharmony_ci	/* enable Timeout BusError */
18962306a36Sopenharmony_ci	if (txx9_ccfg_toeon)
19062306a36Sopenharmony_ci		tx4938_ccfg_set(TX4938_CCFG_TOE);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	/* DMA selection */
19362306a36Sopenharmony_ci	txx9_clear64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_DMASEL_ALL);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	/* Use external clock for external arbiter */
19662306a36Sopenharmony_ci	if (!(____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_PCIARB))
19762306a36Sopenharmony_ci		txx9_clear64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_PCICLKEN_ALL);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	pr_info("%s -- %dMHz(M%dMHz) CRIR:%08x CCFG:%llx PCFG:%llx\n",
20062306a36Sopenharmony_ci		txx9_pcode_str, (cpuclk + 500000) / 1000000,
20162306a36Sopenharmony_ci		(txx9_master_clock + 500000) / 1000000,
20262306a36Sopenharmony_ci		(__u32)____raw_readq(&tx4938_ccfgptr->crir),
20362306a36Sopenharmony_ci		____raw_readq(&tx4938_ccfgptr->ccfg),
20462306a36Sopenharmony_ci		____raw_readq(&tx4938_ccfgptr->pcfg));
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	pr_info("%s SDRAMC --", txx9_pcode_str);
20762306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
20862306a36Sopenharmony_ci		__u64 cr = TX4938_SDRAMC_CR(i);
20962306a36Sopenharmony_ci		unsigned long base, size;
21062306a36Sopenharmony_ci		if (!((__u32)cr & 0x00000400))
21162306a36Sopenharmony_ci			continue;	/* disabled */
21262306a36Sopenharmony_ci		base = (unsigned long)(cr >> 49) << 21;
21362306a36Sopenharmony_ci		size = (((unsigned long)(cr >> 33) & 0x7fff) + 1) << 21;
21462306a36Sopenharmony_ci		pr_cont(" CR%d:%016llx", i, cr);
21562306a36Sopenharmony_ci		tx4938_sdram_resource[i].name = "SDRAM";
21662306a36Sopenharmony_ci		tx4938_sdram_resource[i].start = base;
21762306a36Sopenharmony_ci		tx4938_sdram_resource[i].end = base + size - 1;
21862306a36Sopenharmony_ci		tx4938_sdram_resource[i].flags = IORESOURCE_MEM;
21962306a36Sopenharmony_ci		request_resource(&iomem_resource, &tx4938_sdram_resource[i]);
22062306a36Sopenharmony_ci	}
22162306a36Sopenharmony_ci	pr_cont(" TR:%09llx\n", ____raw_readq(&tx4938_sdramcptr->tr));
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	/* SRAM */
22462306a36Sopenharmony_ci	if (txx9_pcode == 0x4938 && ____raw_readq(&tx4938_sramcptr->cr) & 1) {
22562306a36Sopenharmony_ci		unsigned int size = TX4938_SRAM_SIZE;
22662306a36Sopenharmony_ci		tx4938_sram_resource.name = "SRAM";
22762306a36Sopenharmony_ci		tx4938_sram_resource.start =
22862306a36Sopenharmony_ci			(____raw_readq(&tx4938_sramcptr->cr) >> (39-11))
22962306a36Sopenharmony_ci			& ~(size - 1);
23062306a36Sopenharmony_ci		tx4938_sram_resource.end =
23162306a36Sopenharmony_ci			tx4938_sram_resource.start + TX4938_SRAM_SIZE - 1;
23262306a36Sopenharmony_ci		tx4938_sram_resource.flags = IORESOURCE_MEM;
23362306a36Sopenharmony_ci		request_resource(&iomem_resource, &tx4938_sram_resource);
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	/* TMR */
23762306a36Sopenharmony_ci	/* disable all timers */
23862306a36Sopenharmony_ci	for (i = 0; i < TX4938_NR_TMR; i++)
23962306a36Sopenharmony_ci		txx9_tmr_init(TX4938_TMR_REG(i) & 0xfffffffffULL);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	/* PIO */
24262306a36Sopenharmony_ci	__raw_writel(0, &tx4938_pioptr->maskcpu);
24362306a36Sopenharmony_ci	__raw_writel(0, &tx4938_pioptr->maskext);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	if (txx9_pcode == 0x4938) {
24662306a36Sopenharmony_ci		__u64 pcfg = ____raw_readq(&tx4938_ccfgptr->pcfg);
24762306a36Sopenharmony_ci		/* set PCIC1 reset */
24862306a36Sopenharmony_ci		txx9_set64(&tx4938_ccfgptr->clkctr, TX4938_CLKCTR_PCIC1RST);
24962306a36Sopenharmony_ci		if (pcfg & (TX4938_PCFG_ETH0_SEL | TX4938_PCFG_ETH1_SEL)) {
25062306a36Sopenharmony_ci			mdelay(1);	/* at least 128 cpu clock */
25162306a36Sopenharmony_ci			/* clear PCIC1 reset */
25262306a36Sopenharmony_ci			txx9_clear64(&tx4938_ccfgptr->clkctr,
25362306a36Sopenharmony_ci				     TX4938_CLKCTR_PCIC1RST);
25462306a36Sopenharmony_ci		} else {
25562306a36Sopenharmony_ci			pr_info("%s: stop PCIC1\n", txx9_pcode_str);
25662306a36Sopenharmony_ci			/* stop PCIC1 */
25762306a36Sopenharmony_ci			txx9_set64(&tx4938_ccfgptr->clkctr,
25862306a36Sopenharmony_ci				   TX4938_CLKCTR_PCIC1CKD);
25962306a36Sopenharmony_ci		}
26062306a36Sopenharmony_ci		if (!(pcfg & TX4938_PCFG_ETH0_SEL)) {
26162306a36Sopenharmony_ci			pr_info("%s: stop ETH0\n", txx9_pcode_str);
26262306a36Sopenharmony_ci			txx9_set64(&tx4938_ccfgptr->clkctr,
26362306a36Sopenharmony_ci				   TX4938_CLKCTR_ETH0RST);
26462306a36Sopenharmony_ci			txx9_set64(&tx4938_ccfgptr->clkctr,
26562306a36Sopenharmony_ci				   TX4938_CLKCTR_ETH0CKD);
26662306a36Sopenharmony_ci		}
26762306a36Sopenharmony_ci		if (!(pcfg & TX4938_PCFG_ETH1_SEL)) {
26862306a36Sopenharmony_ci			pr_info("%s: stop ETH1\n", txx9_pcode_str);
26962306a36Sopenharmony_ci			txx9_set64(&tx4938_ccfgptr->clkctr,
27062306a36Sopenharmony_ci				   TX4938_CLKCTR_ETH1RST);
27162306a36Sopenharmony_ci			txx9_set64(&tx4938_ccfgptr->clkctr,
27262306a36Sopenharmony_ci				   TX4938_CLKCTR_ETH1CKD);
27362306a36Sopenharmony_ci		}
27462306a36Sopenharmony_ci	}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	_machine_restart = tx4938_machine_restart;
27762306a36Sopenharmony_ci	board_be_init = tx4938_be_init;
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_civoid __init tx4938_time_init(unsigned int tmrnr)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	if (____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_TINTDIS)
28362306a36Sopenharmony_ci		txx9_clockevent_init(TX4938_TMR_REG(tmrnr) & 0xfffffffffULL,
28462306a36Sopenharmony_ci				     TXX9_IRQ_BASE + TX4938_IR_TMR(tmrnr),
28562306a36Sopenharmony_ci				     TXX9_IMCLK);
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_civoid __init tx4938_sio_init(unsigned int sclk, unsigned int cts_mask)
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	int i;
29162306a36Sopenharmony_ci	unsigned int ch_mask = 0;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	if (__raw_readq(&tx4938_ccfgptr->pcfg) & TX4938_PCFG_ETH0_SEL)
29462306a36Sopenharmony_ci		ch_mask |= 1 << 1; /* disable SIO1 by PCFG setting */
29562306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
29662306a36Sopenharmony_ci		if ((1 << i) & ch_mask)
29762306a36Sopenharmony_ci			continue;
29862306a36Sopenharmony_ci		txx9_sio_init(TX4938_SIO_REG(i) & 0xfffffffffULL,
29962306a36Sopenharmony_ci			      TXX9_IRQ_BASE + TX4938_IR_SIO(i),
30062306a36Sopenharmony_ci			      i, sclk, (1 << i) & cts_mask);
30162306a36Sopenharmony_ci	}
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_civoid __init tx4938_spi_init(int busid)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	txx9_spi_init(busid, TX4938_SPI_REG & 0xfffffffffULL,
30762306a36Sopenharmony_ci		      TXX9_IRQ_BASE + TX4938_IR_SPI);
30862306a36Sopenharmony_ci}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_civoid __init tx4938_ethaddr_init(unsigned char *addr0, unsigned char *addr1)
31162306a36Sopenharmony_ci{
31262306a36Sopenharmony_ci	u64 pcfg = __raw_readq(&tx4938_ccfgptr->pcfg);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	if (addr0 && (pcfg & TX4938_PCFG_ETH0_SEL))
31562306a36Sopenharmony_ci		txx9_ethaddr_init(TXX9_IRQ_BASE + TX4938_IR_ETH0, addr0);
31662306a36Sopenharmony_ci	if (addr1 && (pcfg & TX4938_PCFG_ETH1_SEL))
31762306a36Sopenharmony_ci		txx9_ethaddr_init(TXX9_IRQ_BASE + TX4938_IR_ETH1, addr1);
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_civoid __init tx4938_mtd_init(int ch)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	struct physmap_flash_data pdata = {
32362306a36Sopenharmony_ci		.width = TX4938_EBUSC_WIDTH(ch) / 8,
32462306a36Sopenharmony_ci	};
32562306a36Sopenharmony_ci	unsigned long start = txx9_ce_res[ch].start;
32662306a36Sopenharmony_ci	unsigned long size = txx9_ce_res[ch].end - start + 1;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	if (!(TX4938_EBUSC_CR(ch) & 0x8))
32962306a36Sopenharmony_ci		return; /* disabled */
33062306a36Sopenharmony_ci	txx9_physmap_flash_init(ch, start, size, &pdata);
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_civoid __init tx4938_ata_init(unsigned int irq, unsigned int shift, int tune)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	struct platform_device *pdev;
33662306a36Sopenharmony_ci	struct resource res[] = {
33762306a36Sopenharmony_ci		{
33862306a36Sopenharmony_ci			/* .start and .end are filled in later */
33962306a36Sopenharmony_ci			.flags = IORESOURCE_MEM,
34062306a36Sopenharmony_ci		}, {
34162306a36Sopenharmony_ci			.start = irq,
34262306a36Sopenharmony_ci			.flags = IORESOURCE_IRQ,
34362306a36Sopenharmony_ci		},
34462306a36Sopenharmony_ci	};
34562306a36Sopenharmony_ci	struct tx4938ide_platform_info pdata = {
34662306a36Sopenharmony_ci		.ioport_shift = shift,
34762306a36Sopenharmony_ci		/*
34862306a36Sopenharmony_ci		 * The IDE driver should not change bus timings if other ISA
34962306a36Sopenharmony_ci		 * devices existed.
35062306a36Sopenharmony_ci		 */
35162306a36Sopenharmony_ci		.gbus_clock = tune ? txx9_gbus_clock : 0,
35262306a36Sopenharmony_ci	};
35362306a36Sopenharmony_ci	u64 ebccr;
35462306a36Sopenharmony_ci	int i;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	if ((__raw_readq(&tx4938_ccfgptr->pcfg) &
35762306a36Sopenharmony_ci	     (TX4938_PCFG_ATA_SEL | TX4938_PCFG_NDF_SEL))
35862306a36Sopenharmony_ci	    != TX4938_PCFG_ATA_SEL)
35962306a36Sopenharmony_ci		return;
36062306a36Sopenharmony_ci	for (i = 0; i < 8; i++) {
36162306a36Sopenharmony_ci		/* check EBCCRn.ISA, EBCCRn.BSZ, EBCCRn.ME */
36262306a36Sopenharmony_ci		ebccr = __raw_readq(&tx4938_ebuscptr->cr[i]);
36362306a36Sopenharmony_ci		if ((ebccr & 0x00f00008) == 0x00e00008)
36462306a36Sopenharmony_ci			break;
36562306a36Sopenharmony_ci	}
36662306a36Sopenharmony_ci	if (i == 8)
36762306a36Sopenharmony_ci		return;
36862306a36Sopenharmony_ci	pdata.ebus_ch = i;
36962306a36Sopenharmony_ci	res[0].start = ((ebccr >> 48) << 20) + 0x10000;
37062306a36Sopenharmony_ci	res[0].end = res[0].start + 0x20000 - 1;
37162306a36Sopenharmony_ci	pdev = platform_device_alloc("tx4938ide", -1);
37262306a36Sopenharmony_ci	if (!pdev ||
37362306a36Sopenharmony_ci	    platform_device_add_resources(pdev, res, ARRAY_SIZE(res)) ||
37462306a36Sopenharmony_ci	    platform_device_add_data(pdev, &pdata, sizeof(pdata)) ||
37562306a36Sopenharmony_ci	    platform_device_add(pdev))
37662306a36Sopenharmony_ci		platform_device_put(pdev);
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_civoid __init tx4938_ndfmc_init(unsigned int hold, unsigned int spw)
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	struct txx9ndfmc_platform_data plat_data = {
38262306a36Sopenharmony_ci		.shift = 1,
38362306a36Sopenharmony_ci		.gbus_clock = txx9_gbus_clock,
38462306a36Sopenharmony_ci		.hold = hold,
38562306a36Sopenharmony_ci		.spw = spw,
38662306a36Sopenharmony_ci		.ch_mask = 1,
38762306a36Sopenharmony_ci	};
38862306a36Sopenharmony_ci	unsigned long baseaddr = TX4938_NDFMC_REG & 0xfffffffffULL;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci#ifdef __BIG_ENDIAN
39162306a36Sopenharmony_ci	baseaddr += 4;
39262306a36Sopenharmony_ci#endif
39362306a36Sopenharmony_ci	if ((__raw_readq(&tx4938_ccfgptr->pcfg) &
39462306a36Sopenharmony_ci	     (TX4938_PCFG_ATA_SEL|TX4938_PCFG_ISA_SEL|TX4938_PCFG_NDF_SEL)) ==
39562306a36Sopenharmony_ci	    TX4938_PCFG_NDF_SEL)
39662306a36Sopenharmony_ci		txx9_ndfmc_init(baseaddr, &plat_data);
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_civoid __init tx4938_dmac_init(int memcpy_chan0, int memcpy_chan1)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	struct txx9dmac_platform_data plat_data = {
40262306a36Sopenharmony_ci		.have_64bit_regs = true,
40362306a36Sopenharmony_ci	};
40462306a36Sopenharmony_ci	int i;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
40762306a36Sopenharmony_ci		plat_data.memcpy_chan = i ? memcpy_chan1 : memcpy_chan0;
40862306a36Sopenharmony_ci		txx9_dmac_init(i, TX4938_DMA_REG(i) & 0xfffffffffULL,
40962306a36Sopenharmony_ci			       TXX9_IRQ_BASE + TX4938_IR_DMA(i, 0),
41062306a36Sopenharmony_ci			       &plat_data);
41162306a36Sopenharmony_ci	}
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_civoid __init tx4938_aclc_init(void)
41562306a36Sopenharmony_ci{
41662306a36Sopenharmony_ci	u64 pcfg = __raw_readq(&tx4938_ccfgptr->pcfg);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	if ((pcfg & TX4938_PCFG_SEL2) &&
41962306a36Sopenharmony_ci	    !(pcfg & TX4938_PCFG_ETH0_SEL))
42062306a36Sopenharmony_ci		txx9_aclc_init(TX4938_ACLC_REG & 0xfffffffffULL,
42162306a36Sopenharmony_ci			       TXX9_IRQ_BASE + TX4938_IR_ACLC,
42262306a36Sopenharmony_ci			       1, 0, 1);
42362306a36Sopenharmony_ci}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_civoid __init tx4938_sramc_init(void)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	if (tx4938_sram_resource.start)
42862306a36Sopenharmony_ci		txx9_sramc_init(&tx4938_sram_resource);
42962306a36Sopenharmony_ci}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_cistatic void __init tx4938_stop_unused_modules(void)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	__u64 pcfg, rst = 0, ckd = 0;
43462306a36Sopenharmony_ci	char buf[128];
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	buf[0] = '\0';
43762306a36Sopenharmony_ci	local_irq_disable();
43862306a36Sopenharmony_ci	pcfg = ____raw_readq(&tx4938_ccfgptr->pcfg);
43962306a36Sopenharmony_ci	switch (txx9_pcode) {
44062306a36Sopenharmony_ci	case 0x4937:
44162306a36Sopenharmony_ci		if (!(pcfg & TX4938_PCFG_SEL2)) {
44262306a36Sopenharmony_ci			rst |= TX4938_CLKCTR_ACLRST;
44362306a36Sopenharmony_ci			ckd |= TX4938_CLKCTR_ACLCKD;
44462306a36Sopenharmony_ci			strcat(buf, " ACLC");
44562306a36Sopenharmony_ci		}
44662306a36Sopenharmony_ci		break;
44762306a36Sopenharmony_ci	case 0x4938:
44862306a36Sopenharmony_ci		if (!(pcfg & TX4938_PCFG_SEL2) ||
44962306a36Sopenharmony_ci		    (pcfg & TX4938_PCFG_ETH0_SEL)) {
45062306a36Sopenharmony_ci			rst |= TX4938_CLKCTR_ACLRST;
45162306a36Sopenharmony_ci			ckd |= TX4938_CLKCTR_ACLCKD;
45262306a36Sopenharmony_ci			strcat(buf, " ACLC");
45362306a36Sopenharmony_ci		}
45462306a36Sopenharmony_ci		if ((pcfg &
45562306a36Sopenharmony_ci		     (TX4938_PCFG_ATA_SEL | TX4938_PCFG_ISA_SEL |
45662306a36Sopenharmony_ci		      TX4938_PCFG_NDF_SEL))
45762306a36Sopenharmony_ci		    != TX4938_PCFG_NDF_SEL) {
45862306a36Sopenharmony_ci			rst |= TX4938_CLKCTR_NDFRST;
45962306a36Sopenharmony_ci			ckd |= TX4938_CLKCTR_NDFCKD;
46062306a36Sopenharmony_ci			strcat(buf, " NDFMC");
46162306a36Sopenharmony_ci		}
46262306a36Sopenharmony_ci		if (!(pcfg & TX4938_PCFG_SPI_SEL)) {
46362306a36Sopenharmony_ci			rst |= TX4938_CLKCTR_SPIRST;
46462306a36Sopenharmony_ci			ckd |= TX4938_CLKCTR_SPICKD;
46562306a36Sopenharmony_ci			strcat(buf, " SPI");
46662306a36Sopenharmony_ci		}
46762306a36Sopenharmony_ci		break;
46862306a36Sopenharmony_ci	}
46962306a36Sopenharmony_ci	if (rst | ckd) {
47062306a36Sopenharmony_ci		txx9_set64(&tx4938_ccfgptr->clkctr, rst);
47162306a36Sopenharmony_ci		txx9_set64(&tx4938_ccfgptr->clkctr, ckd);
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci	local_irq_enable();
47462306a36Sopenharmony_ci	if (buf[0])
47562306a36Sopenharmony_ci		pr_info("%s: stop%s\n", txx9_pcode_str, buf);
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic int __init tx4938_late_init(void)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci	if (txx9_pcode != 0x4937 && txx9_pcode != 0x4938)
48162306a36Sopenharmony_ci		return -ENODEV;
48262306a36Sopenharmony_ci	tx4938_stop_unused_modules();
48362306a36Sopenharmony_ci	return 0;
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_cilate_initcall(tx4938_late_init);
486