| Atsushi Nemoto | 94a4c32 | 2008-07-19 01:51:47 +0900 | [diff] [blame] | 1 | /* | 
 | 2 |  * TX4938/4937 setup routines | 
 | 3 |  * Based on linux/arch/mips/txx9/rbtx4938/setup.c, | 
 | 4 |  *	    and RBTX49xx patch from CELF patch archive. | 
 | 5 |  * | 
 | 6 |  * 2003-2005 (c) MontaVista Software, Inc. | 
 | 7 |  * (C) Copyright TOSHIBA CORPORATION 2000-2001, 2004-2007 | 
 | 8 |  * | 
 | 9 |  * This file is subject to the terms and conditions of the GNU General Public | 
 | 10 |  * License.  See the file "COPYING" in the main directory of this archive | 
 | 11 |  * for more details. | 
 | 12 |  */ | 
 | 13 | #include <linux/init.h> | 
 | 14 | #include <linux/ioport.h> | 
 | 15 | #include <linux/delay.h> | 
 | 16 | #include <linux/serial_core.h> | 
 | 17 | #include <linux/param.h> | 
 | 18 | #include <asm/txx9irq.h> | 
 | 19 | #include <asm/txx9tmr.h> | 
 | 20 | #include <asm/txx9pio.h> | 
 | 21 | #include <asm/txx9/generic.h> | 
 | 22 | #include <asm/txx9/tx4938.h> | 
 | 23 |  | 
 | 24 | void __init tx4938_wdr_init(void) | 
 | 25 | { | 
 | 26 | 	/* clear WatchDogReset (W1C) */ | 
 | 27 | 	tx4938_ccfg_set(TX4938_CCFG_WDRST); | 
 | 28 | 	/* do reset on watchdog */ | 
 | 29 | 	tx4938_ccfg_set(TX4938_CCFG_WR); | 
 | 30 | } | 
 | 31 |  | 
 | 32 | static struct resource tx4938_sdram_resource[4]; | 
 | 33 | static struct resource tx4938_sram_resource; | 
 | 34 |  | 
 | 35 | #define TX4938_SRAM_SIZE 0x800 | 
 | 36 |  | 
 | 37 | void __init tx4938_setup(void) | 
 | 38 | { | 
 | 39 | 	int i; | 
 | 40 | 	__u32 divmode; | 
 | 41 | 	int cpuclk = 0; | 
 | 42 | 	u64 ccfg; | 
 | 43 |  | 
 | 44 | 	txx9_reg_res_init(TX4938_REV_PCODE(), TX4938_REG_BASE, | 
 | 45 | 			  TX4938_REG_SIZE); | 
 | 46 |  | 
 | 47 | 	/* SDRAMC,EBUSC are configured by PROM */ | 
 | 48 | 	for (i = 0; i < 8; i++) { | 
 | 49 | 		if (!(TX4938_EBUSC_CR(i) & 0x8)) | 
 | 50 | 			continue;	/* disabled */ | 
 | 51 | 		txx9_ce_res[i].start = (unsigned long)TX4938_EBUSC_BA(i); | 
 | 52 | 		txx9_ce_res[i].end = | 
 | 53 | 			txx9_ce_res[i].start + TX4938_EBUSC_SIZE(i) - 1; | 
 | 54 | 		request_resource(&iomem_resource, &txx9_ce_res[i]); | 
 | 55 | 	} | 
 | 56 |  | 
 | 57 | 	/* clocks */ | 
 | 58 | 	ccfg = ____raw_readq(&tx4938_ccfgptr->ccfg); | 
 | 59 | 	if (txx9_master_clock) { | 
 | 60 | 		/* calculate gbus_clock and cpu_clock from master_clock */ | 
 | 61 | 		divmode = (__u32)ccfg & TX4938_CCFG_DIVMODE_MASK; | 
 | 62 | 		switch (divmode) { | 
 | 63 | 		case TX4938_CCFG_DIVMODE_8: | 
 | 64 | 		case TX4938_CCFG_DIVMODE_10: | 
 | 65 | 		case TX4938_CCFG_DIVMODE_12: | 
 | 66 | 		case TX4938_CCFG_DIVMODE_16: | 
 | 67 | 		case TX4938_CCFG_DIVMODE_18: | 
 | 68 | 			txx9_gbus_clock = txx9_master_clock * 4; break; | 
 | 69 | 		default: | 
 | 70 | 			txx9_gbus_clock = txx9_master_clock; | 
 | 71 | 		} | 
 | 72 | 		switch (divmode) { | 
 | 73 | 		case TX4938_CCFG_DIVMODE_2: | 
 | 74 | 		case TX4938_CCFG_DIVMODE_8: | 
 | 75 | 			cpuclk = txx9_gbus_clock * 2; break; | 
 | 76 | 		case TX4938_CCFG_DIVMODE_2_5: | 
 | 77 | 		case TX4938_CCFG_DIVMODE_10: | 
 | 78 | 			cpuclk = txx9_gbus_clock * 5 / 2; break; | 
 | 79 | 		case TX4938_CCFG_DIVMODE_3: | 
 | 80 | 		case TX4938_CCFG_DIVMODE_12: | 
 | 81 | 			cpuclk = txx9_gbus_clock * 3; break; | 
 | 82 | 		case TX4938_CCFG_DIVMODE_4: | 
 | 83 | 		case TX4938_CCFG_DIVMODE_16: | 
 | 84 | 			cpuclk = txx9_gbus_clock * 4; break; | 
 | 85 | 		case TX4938_CCFG_DIVMODE_4_5: | 
 | 86 | 		case TX4938_CCFG_DIVMODE_18: | 
 | 87 | 			cpuclk = txx9_gbus_clock * 9 / 2; break; | 
 | 88 | 		} | 
 | 89 | 		txx9_cpu_clock = cpuclk; | 
 | 90 | 	} else { | 
 | 91 | 		if (txx9_cpu_clock == 0) | 
 | 92 | 			txx9_cpu_clock = 300000000;	/* 300MHz */ | 
 | 93 | 		/* calculate gbus_clock and master_clock from cpu_clock */ | 
 | 94 | 		cpuclk = txx9_cpu_clock; | 
 | 95 | 		divmode = (__u32)ccfg & TX4938_CCFG_DIVMODE_MASK; | 
 | 96 | 		switch (divmode) { | 
 | 97 | 		case TX4938_CCFG_DIVMODE_2: | 
 | 98 | 		case TX4938_CCFG_DIVMODE_8: | 
 | 99 | 			txx9_gbus_clock = cpuclk / 2; break; | 
 | 100 | 		case TX4938_CCFG_DIVMODE_2_5: | 
 | 101 | 		case TX4938_CCFG_DIVMODE_10: | 
 | 102 | 			txx9_gbus_clock = cpuclk * 2 / 5; break; | 
 | 103 | 		case TX4938_CCFG_DIVMODE_3: | 
 | 104 | 		case TX4938_CCFG_DIVMODE_12: | 
 | 105 | 			txx9_gbus_clock = cpuclk / 3; break; | 
 | 106 | 		case TX4938_CCFG_DIVMODE_4: | 
 | 107 | 		case TX4938_CCFG_DIVMODE_16: | 
 | 108 | 			txx9_gbus_clock = cpuclk / 4; break; | 
 | 109 | 		case TX4938_CCFG_DIVMODE_4_5: | 
 | 110 | 		case TX4938_CCFG_DIVMODE_18: | 
 | 111 | 			txx9_gbus_clock = cpuclk * 2 / 9; break; | 
 | 112 | 		} | 
 | 113 | 		switch (divmode) { | 
 | 114 | 		case TX4938_CCFG_DIVMODE_8: | 
 | 115 | 		case TX4938_CCFG_DIVMODE_10: | 
 | 116 | 		case TX4938_CCFG_DIVMODE_12: | 
 | 117 | 		case TX4938_CCFG_DIVMODE_16: | 
 | 118 | 		case TX4938_CCFG_DIVMODE_18: | 
 | 119 | 			txx9_master_clock = txx9_gbus_clock / 4; break; | 
 | 120 | 		default: | 
 | 121 | 			txx9_master_clock = txx9_gbus_clock; | 
 | 122 | 		} | 
 | 123 | 	} | 
 | 124 | 	/* change default value to udelay/mdelay take reasonable time */ | 
 | 125 | 	loops_per_jiffy = txx9_cpu_clock / HZ / 2; | 
 | 126 |  | 
 | 127 | 	/* CCFG */ | 
 | 128 | 	tx4938_wdr_init(); | 
 | 129 | 	/* clear BusErrorOnWrite flag (W1C) */ | 
 | 130 | 	tx4938_ccfg_set(TX4938_CCFG_BEOW); | 
 | 131 | 	/* enable Timeout BusError */ | 
 | 132 | 	if (txx9_ccfg_toeon) | 
 | 133 | 		tx4938_ccfg_set(TX4938_CCFG_TOE); | 
 | 134 |  | 
 | 135 | 	/* DMA selection */ | 
 | 136 | 	txx9_clear64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_DMASEL_ALL); | 
 | 137 |  | 
 | 138 | 	/* Use external clock for external arbiter */ | 
 | 139 | 	if (!(____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_PCIARB)) | 
 | 140 | 		txx9_clear64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_PCICLKEN_ALL); | 
 | 141 |  | 
 | 142 | 	printk(KERN_INFO "%s -- %dMHz(M%dMHz) CRIR:%08x CCFG:%llx PCFG:%llx\n", | 
 | 143 | 	       txx9_pcode_str, | 
 | 144 | 	       (cpuclk + 500000) / 1000000, | 
 | 145 | 	       (txx9_master_clock + 500000) / 1000000, | 
 | 146 | 	       (__u32)____raw_readq(&tx4938_ccfgptr->crir), | 
 | 147 | 	       (unsigned long long)____raw_readq(&tx4938_ccfgptr->ccfg), | 
 | 148 | 	       (unsigned long long)____raw_readq(&tx4938_ccfgptr->pcfg)); | 
 | 149 |  | 
 | 150 | 	printk(KERN_INFO "%s SDRAMC --", txx9_pcode_str); | 
 | 151 | 	for (i = 0; i < 4; i++) { | 
 | 152 | 		__u64 cr = TX4938_SDRAMC_CR(i); | 
 | 153 | 		unsigned long base, size; | 
 | 154 | 		if (!((__u32)cr & 0x00000400)) | 
 | 155 | 			continue;	/* disabled */ | 
 | 156 | 		base = (unsigned long)(cr >> 49) << 21; | 
 | 157 | 		size = (((unsigned long)(cr >> 33) & 0x7fff) + 1) << 21; | 
 | 158 | 		printk(" CR%d:%016llx", i, (unsigned long long)cr); | 
 | 159 | 		tx4938_sdram_resource[i].name = "SDRAM"; | 
 | 160 | 		tx4938_sdram_resource[i].start = base; | 
 | 161 | 		tx4938_sdram_resource[i].end = base + size - 1; | 
 | 162 | 		tx4938_sdram_resource[i].flags = IORESOURCE_MEM; | 
 | 163 | 		request_resource(&iomem_resource, &tx4938_sdram_resource[i]); | 
 | 164 | 	} | 
 | 165 | 	printk(" TR:%09llx\n", | 
 | 166 | 	       (unsigned long long)____raw_readq(&tx4938_sdramcptr->tr)); | 
 | 167 |  | 
 | 168 | 	/* SRAM */ | 
 | 169 | 	if (txx9_pcode == 0x4938 && ____raw_readq(&tx4938_sramcptr->cr) & 1) { | 
 | 170 | 		unsigned int size = TX4938_SRAM_SIZE; | 
 | 171 | 		tx4938_sram_resource.name = "SRAM"; | 
 | 172 | 		tx4938_sram_resource.start = | 
 | 173 | 			(____raw_readq(&tx4938_sramcptr->cr) >> (39-11)) | 
 | 174 | 			& ~(size - 1); | 
 | 175 | 		tx4938_sram_resource.end = | 
 | 176 | 			tx4938_sram_resource.start + TX4938_SRAM_SIZE - 1; | 
 | 177 | 		tx4938_sram_resource.flags = IORESOURCE_MEM; | 
 | 178 | 		request_resource(&iomem_resource, &tx4938_sram_resource); | 
 | 179 | 	} | 
 | 180 |  | 
 | 181 | 	/* TMR */ | 
 | 182 | 	/* disable all timers */ | 
 | 183 | 	for (i = 0; i < TX4938_NR_TMR; i++) | 
 | 184 | 		txx9_tmr_init(TX4938_TMR_REG(i) & 0xfffffffffULL); | 
 | 185 |  | 
 | 186 | 	/* DMA */ | 
 | 187 | 	for (i = 0; i < 2; i++) | 
 | 188 | 		____raw_writeq(TX4938_DMA_MCR_MSTEN, | 
 | 189 | 			       (void __iomem *)(TX4938_DMA_REG(i) + 0x50)); | 
 | 190 |  | 
 | 191 | 	/* PIO */ | 
 | 192 | 	txx9_gpio_init(TX4938_PIO_REG & 0xfffffffffULL, 0, TX4938_NUM_PIO); | 
 | 193 | 	__raw_writel(0, &tx4938_pioptr->maskcpu); | 
 | 194 | 	__raw_writel(0, &tx4938_pioptr->maskext); | 
 | 195 |  | 
 | 196 | 	if (txx9_pcode == 0x4938) { | 
 | 197 | 		__u64 pcfg = ____raw_readq(&tx4938_ccfgptr->pcfg); | 
 | 198 | 		/* set PCIC1 reset */ | 
 | 199 | 		txx9_set64(&tx4938_ccfgptr->clkctr, TX4938_CLKCTR_PCIC1RST); | 
 | 200 | 		if (pcfg & (TX4938_PCFG_ETH0_SEL | TX4938_PCFG_ETH1_SEL)) { | 
 | 201 | 			mdelay(1);	/* at least 128 cpu clock */ | 
 | 202 | 			/* clear PCIC1 reset */ | 
 | 203 | 			txx9_clear64(&tx4938_ccfgptr->clkctr, | 
 | 204 | 				     TX4938_CLKCTR_PCIC1RST); | 
 | 205 | 		} else { | 
 | 206 | 			printk(KERN_INFO "%s: stop PCIC1\n", txx9_pcode_str); | 
 | 207 | 			/* stop PCIC1 */ | 
 | 208 | 			txx9_set64(&tx4938_ccfgptr->clkctr, | 
 | 209 | 				   TX4938_CLKCTR_PCIC1CKD); | 
 | 210 | 		} | 
 | 211 | 		if (!(pcfg & TX4938_PCFG_ETH0_SEL)) { | 
 | 212 | 			printk(KERN_INFO "%s: stop ETH0\n", txx9_pcode_str); | 
 | 213 | 			txx9_set64(&tx4938_ccfgptr->clkctr, | 
 | 214 | 				   TX4938_CLKCTR_ETH0RST); | 
 | 215 | 			txx9_set64(&tx4938_ccfgptr->clkctr, | 
 | 216 | 				   TX4938_CLKCTR_ETH0CKD); | 
 | 217 | 		} | 
 | 218 | 		if (!(pcfg & TX4938_PCFG_ETH1_SEL)) { | 
 | 219 | 			printk(KERN_INFO "%s: stop ETH1\n", txx9_pcode_str); | 
 | 220 | 			txx9_set64(&tx4938_ccfgptr->clkctr, | 
 | 221 | 				   TX4938_CLKCTR_ETH1RST); | 
 | 222 | 			txx9_set64(&tx4938_ccfgptr->clkctr, | 
 | 223 | 				   TX4938_CLKCTR_ETH1CKD); | 
 | 224 | 		} | 
 | 225 | 	} | 
 | 226 | } | 
 | 227 |  | 
 | 228 | void __init tx4938_time_init(unsigned int tmrnr) | 
 | 229 | { | 
 | 230 | 	if (____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_TINTDIS) | 
 | 231 | 		txx9_clockevent_init(TX4938_TMR_REG(tmrnr) & 0xfffffffffULL, | 
 | 232 | 				     TXX9_IRQ_BASE + TX4938_IR_TMR(tmrnr), | 
 | 233 | 				     TXX9_IMCLK); | 
 | 234 | } | 
 | 235 |  | 
 | 236 | void __init tx4938_setup_serial(void) | 
 | 237 | { | 
 | 238 | #ifdef CONFIG_SERIAL_TXX9 | 
 | 239 | 	int i; | 
 | 240 | 	struct uart_port req; | 
 | 241 | 	unsigned int ch_mask = 0; | 
 | 242 |  | 
 | 243 | 	if (__raw_readq(&tx4938_ccfgptr->pcfg) & TX4938_PCFG_ETH0_SEL) | 
 | 244 | 		ch_mask |= 1 << 1; /* disable SIO1 by PCFG setting */ | 
 | 245 | 	for (i = 0; i < 2; i++) { | 
 | 246 | 		if ((1 << i) & ch_mask) | 
 | 247 | 			continue; | 
 | 248 | 		memset(&req, 0, sizeof(req)); | 
 | 249 | 		req.line = i; | 
 | 250 | 		req.iotype = UPIO_MEM; | 
 | 251 | 		req.membase = (unsigned char __iomem *)TX4938_SIO_REG(i); | 
 | 252 | 		req.mapbase = TX4938_SIO_REG(i) & 0xfffffffffULL; | 
 | 253 | 		req.irq = TXX9_IRQ_BASE + TX4938_IR_SIO(i); | 
 | 254 | 		req.flags |= UPF_BUGGY_UART /*HAVE_CTS_LINE*/; | 
 | 255 | 		req.uartclk = TXX9_IMCLK; | 
 | 256 | 		early_serial_txx9_setup(&req); | 
 | 257 | 	} | 
 | 258 | #endif /* CONFIG_SERIAL_TXX9 */ | 
 | 259 | } |