| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2 |  * Common code for the boards based on Freescale MPC52xx embedded CPU. | 
 | 3 |  * | 
 | 4 |  *  | 
 | 5 |  * Maintainer : Sylvain Munaut <tnt@246tNt.com> | 
 | 6 |  * | 
 | 7 |  * Support for other bootloaders than UBoot by Dale Farnsworth  | 
 | 8 |  * <dfarnsworth@mvista.com> | 
 | 9 |  *  | 
 | 10 |  * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com> | 
 | 11 |  * Copyright (C) 2003 Montavista Software, Inc | 
 | 12 |  *  | 
 | 13 |  * This file is licensed under the terms of the GNU General Public License | 
 | 14 |  * version 2. This program is licensed "as is" without any warranty of any | 
 | 15 |  * kind, whether express or implied. | 
 | 16 |  */ | 
 | 17 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 18 |  | 
 | 19 | #include <asm/io.h> | 
 | 20 | #include <asm/time.h> | 
 | 21 | #include <asm/mpc52xx.h> | 
 | 22 | #include <asm/mpc52xx_psc.h> | 
 | 23 | #include <asm/pgtable.h> | 
 | 24 | #include <asm/ppcboot.h> | 
 | 25 |  | 
| Sylvain Munaut | 1f5e3b0 | 2006-03-26 13:38:09 +0200 | [diff] [blame] | 26 | #include <syslib/mpc52xx_pci.h> | 
 | 27 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 28 | extern bd_t __res; | 
 | 29 |  | 
 | 30 | static int core_mult[] = {		/* CPU Frequency multiplier, taken    */ | 
 | 31 | 	0,  0,  0,  10, 20, 20, 25, 45,	/* from the datasheet used to compute */ | 
 | 32 | 	30, 55, 40, 50, 0,  60, 35, 0,	/* CPU frequency from XLB freq and    */ | 
 | 33 | 	30, 25, 65, 10, 70, 20, 75, 45,	/* external jumper config             */ | 
 | 34 | 	0,  55, 40, 50, 80, 60, 35, 0 | 
 | 35 | }; | 
 | 36 |  | 
 | 37 | void | 
 | 38 | mpc52xx_restart(char *cmd) | 
 | 39 | { | 
 | 40 | 	struct mpc52xx_gpt __iomem *gpt0 = MPC52xx_VA(MPC52xx_GPTx_OFFSET(0)); | 
 | 41 |  | 
 | 42 | 	local_irq_disable(); | 
 | 43 |  | 
 | 44 | 	/* Turn on the watchdog and wait for it to expire. It effectively | 
 | 45 | 	  does a reset */ | 
 | 46 | 	out_be32(&gpt0->count, 0x000000ff); | 
 | 47 | 	out_be32(&gpt0->mode, 0x00009004); | 
 | 48 |  | 
 | 49 | 	while (1); | 
 | 50 | } | 
 | 51 |  | 
 | 52 | void | 
 | 53 | mpc52xx_halt(void) | 
 | 54 | { | 
 | 55 | 	local_irq_disable(); | 
 | 56 |  | 
 | 57 | 	while (1); | 
 | 58 | } | 
 | 59 |  | 
 | 60 | void | 
 | 61 | mpc52xx_power_off(void) | 
 | 62 | { | 
 | 63 | 	/* By default we don't have any way of shut down. | 
 | 64 | 	   If a specific board wants to, it can set the power down | 
 | 65 | 	   code to any hardware implementation dependent code */ | 
 | 66 | 	mpc52xx_halt(); | 
 | 67 | } | 
 | 68 |  | 
 | 69 |  | 
 | 70 | void __init | 
 | 71 | mpc52xx_set_bat(void) | 
 | 72 | { | 
 | 73 | 	/* Set BAT 2 to map the 0xf0000000 area */ | 
 | 74 | 	/* This mapping is used during mpc52xx_progress, | 
 | 75 | 	 * mpc52xx_find_end_of_memory, and UARTs/GPIO access for debug | 
 | 76 | 	 */ | 
 | 77 | 	mb(); | 
 | 78 | 	mtspr(SPRN_DBAT2U, 0xf0001ffe); | 
 | 79 | 	mtspr(SPRN_DBAT2L, 0xf000002a); | 
 | 80 | 	mb(); | 
 | 81 | } | 
 | 82 |  | 
 | 83 | void __init | 
 | 84 | mpc52xx_map_io(void) | 
 | 85 | { | 
| Sylvain Munaut | 4aa7c80 | 2006-01-06 00:11:34 -0800 | [diff] [blame] | 86 | 	/* Here we map the MBAR and the whole upper zone. MBAR is only | 
 | 87 | 	   64k but we can't map only 64k with BATs. Map the whole | 
 | 88 | 	   0xf0000000 range is ok and helps eventual lpb devices placed there */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 89 | 	io_block_mapping( | 
| Sylvain Munaut | 4aa7c80 | 2006-01-06 00:11:34 -0800 | [diff] [blame] | 90 | 		MPC52xx_MBAR_VIRT, MPC52xx_MBAR, 0x10000000, _PAGE_IO); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 91 | } | 
 | 92 |  | 
 | 93 |  | 
 | 94 | #ifdef CONFIG_SERIAL_TEXT_DEBUG | 
 | 95 | #ifndef MPC52xx_PF_CONSOLE_PORT | 
 | 96 | #error "mpc52xx PSC for console not selected" | 
 | 97 | #endif | 
 | 98 |  | 
 | 99 | static void | 
 | 100 | mpc52xx_psc_putc(struct mpc52xx_psc __iomem *psc, unsigned char c) | 
 | 101 | { | 
 | 102 | 	while (!(in_be16(&psc->mpc52xx_psc_status) & | 
 | 103 | 	         MPC52xx_PSC_SR_TXRDY)); | 
 | 104 | 	out_8(&psc->mpc52xx_psc_buffer_8, c); | 
 | 105 | } | 
 | 106 |  | 
 | 107 | void | 
 | 108 | mpc52xx_progress(char *s, unsigned short hex) | 
 | 109 | { | 
 | 110 | 	char c; | 
 | 111 | 	struct mpc52xx_psc __iomem *psc; | 
 | 112 |  | 
 | 113 | 	psc = MPC52xx_VA(MPC52xx_PSCx_OFFSET(MPC52xx_PF_CONSOLE_PORT)); | 
 | 114 |  | 
 | 115 | 	while ((c = *s++) != 0) { | 
 | 116 | 		if (c == '\n') | 
 | 117 | 			mpc52xx_psc_putc(psc, '\r'); | 
 | 118 | 		mpc52xx_psc_putc(psc, c); | 
 | 119 | 	} | 
 | 120 |  | 
 | 121 | 	mpc52xx_psc_putc(psc, '\r'); | 
 | 122 | 	mpc52xx_psc_putc(psc, '\n'); | 
 | 123 | } | 
 | 124 |  | 
 | 125 | #endif  /* CONFIG_SERIAL_TEXT_DEBUG */ | 
 | 126 |  | 
 | 127 |  | 
 | 128 | unsigned long __init | 
 | 129 | mpc52xx_find_end_of_memory(void) | 
 | 130 | { | 
 | 131 | 	u32 ramsize = __res.bi_memsize; | 
 | 132 |  | 
 | 133 | 	/* | 
 | 134 | 	 * if bootloader passed a memsize, just use it | 
 | 135 | 	 * else get size from sdram config registers | 
 | 136 | 	 */ | 
 | 137 | 	if (ramsize == 0) { | 
 | 138 | 		struct mpc52xx_mmap_ctl __iomem *mmap_ctl; | 
 | 139 | 		u32 sdram_config_0, sdram_config_1; | 
 | 140 |  | 
 | 141 | 		/* Temp BAT2 mapping active when this is called ! */ | 
 | 142 | 		mmap_ctl = MPC52xx_VA(MPC52xx_MMAP_CTL_OFFSET); | 
 | 143 |  | 
 | 144 | 		sdram_config_0 = in_be32(&mmap_ctl->sdram0); | 
 | 145 | 		sdram_config_1 = in_be32(&mmap_ctl->sdram1); | 
 | 146 |  | 
 | 147 | 		if ((sdram_config_0 & 0x1f) >= 0x13) | 
 | 148 | 			ramsize = 1 << ((sdram_config_0 & 0xf) + 17); | 
 | 149 |  | 
 | 150 | 		if (((sdram_config_1 & 0x1f) >= 0x13) && | 
 | 151 | 				((sdram_config_1 & 0xfff00000) == ramsize)) | 
 | 152 | 			ramsize += 1 << ((sdram_config_1 & 0xf) + 17); | 
 | 153 | 	} | 
 | 154 |  | 
 | 155 | 	return ramsize; | 
 | 156 | } | 
 | 157 |  | 
 | 158 | void __init | 
 | 159 | mpc52xx_calibrate_decr(void) | 
 | 160 | { | 
 | 161 | 	int current_time, previous_time; | 
 | 162 | 	int tbl_start, tbl_end; | 
 | 163 | 	unsigned int xlbfreq, cpufreq, ipbfreq, pcifreq, divisor; | 
 | 164 |  | 
 | 165 | 	xlbfreq = __res.bi_busfreq; | 
 | 166 | 	/* if bootloader didn't pass bus frequencies, calculate them */ | 
 | 167 | 	if (xlbfreq == 0) { | 
 | 168 | 		/* Get RTC & Clock manager modules */ | 
 | 169 | 		struct mpc52xx_rtc __iomem *rtc; | 
 | 170 | 		struct mpc52xx_cdm __iomem *cdm; | 
 | 171 |  | 
 | 172 | 		rtc = ioremap(MPC52xx_PA(MPC52xx_RTC_OFFSET), MPC52xx_RTC_SIZE); | 
 | 173 | 		cdm = ioremap(MPC52xx_PA(MPC52xx_CDM_OFFSET), MPC52xx_CDM_SIZE); | 
 | 174 |  | 
 | 175 | 		if ((rtc==NULL) || (cdm==NULL)) | 
 | 176 | 			panic("Can't ioremap RTC/CDM while computing bus freq"); | 
 | 177 |  | 
 | 178 | 		/* Count bus clock during 1/64 sec */ | 
 | 179 | 		out_be32(&rtc->dividers, 0x8f1f0000);	/* Set RTC 64x faster */ | 
 | 180 | 		previous_time = in_be32(&rtc->time); | 
 | 181 | 		while ((current_time = in_be32(&rtc->time)) == previous_time) ; | 
 | 182 | 		tbl_start = get_tbl(); | 
 | 183 | 		previous_time = current_time; | 
 | 184 | 		while ((current_time = in_be32(&rtc->time)) == previous_time) ; | 
 | 185 | 		tbl_end = get_tbl(); | 
 | 186 | 		out_be32(&rtc->dividers, 0xffff0000);	/* Restore RTC */ | 
 | 187 |  | 
 | 188 | 		/* Compute all frequency from that & CDM settings */ | 
 | 189 | 		xlbfreq = (tbl_end - tbl_start) << 8; | 
 | 190 | 		cpufreq = (xlbfreq * core_mult[in_be32(&cdm->rstcfg)&0x1f])/10; | 
 | 191 | 		ipbfreq = (in_8(&cdm->ipb_clk_sel) & 1) ? | 
 | 192 | 					xlbfreq / 2 : xlbfreq; | 
 | 193 | 		switch (in_8(&cdm->pci_clk_sel) & 3) { | 
 | 194 | 		case 0: | 
 | 195 | 			pcifreq = ipbfreq; | 
 | 196 | 			break; | 
 | 197 | 		case 1: | 
 | 198 | 			pcifreq = ipbfreq / 2; | 
 | 199 | 			break; | 
 | 200 | 		default: | 
 | 201 | 			pcifreq = xlbfreq / 4; | 
 | 202 | 			break; | 
 | 203 | 		} | 
 | 204 | 		__res.bi_busfreq = xlbfreq; | 
 | 205 | 		__res.bi_intfreq = cpufreq; | 
 | 206 | 		__res.bi_ipbfreq = ipbfreq; | 
 | 207 | 		__res.bi_pcifreq = pcifreq; | 
 | 208 |  | 
 | 209 | 		/* Release mapping */ | 
 | 210 | 		iounmap(rtc); | 
 | 211 | 		iounmap(cdm); | 
 | 212 | 	} | 
 | 213 |  | 
 | 214 | 	divisor = 4; | 
 | 215 |  | 
 | 216 | 	tb_ticks_per_jiffy = xlbfreq / HZ / divisor; | 
 | 217 | 	tb_to_us = mulhwu_scale_factor(xlbfreq / divisor, 1000000); | 
 | 218 | } | 
 | 219 |  | 
| Sylvain Munaut | 1f5e3b0 | 2006-03-26 13:38:09 +0200 | [diff] [blame] | 220 |  | 
 | 221 | void __init | 
 | 222 | mpc52xx_setup_cpu(void) | 
 | 223 | { | 
 | 224 | 	struct mpc52xx_cdm  __iomem *cdm; | 
 | 225 | 	struct mpc52xx_xlb  __iomem *xlb; | 
 | 226 |  | 
 | 227 | 	/* Map zones */ | 
 | 228 | 	cdm  = ioremap(MPC52xx_PA(MPC52xx_CDM_OFFSET), MPC52xx_CDM_SIZE); | 
 | 229 | 	xlb  = ioremap(MPC52xx_PA(MPC52xx_XLB_OFFSET), MPC52xx_XLB_SIZE); | 
 | 230 |  | 
 | 231 | 	if (!cdm || !xlb) { | 
 | 232 | 		printk(KERN_ERR __FILE__ ": " | 
 | 233 | 			"Error while mapping CDM/XLB during " | 
 | 234 | 			"mpc52xx_setup_cpu\n"); | 
 | 235 | 		goto unmap_regs; | 
 | 236 | 	} | 
 | 237 |  | 
 | 238 | 	/* Use internal 48 Mhz */ | 
 | 239 | 	out_8(&cdm->ext_48mhz_en, 0x00); | 
 | 240 | 	out_8(&cdm->fd_enable, 0x01); | 
 | 241 | 	if (in_be32(&cdm->rstcfg) & 0x40)	/* Assumes 33Mhz clock */ | 
 | 242 | 		out_be16(&cdm->fd_counters, 0x0001); | 
 | 243 | 	else | 
 | 244 | 		out_be16(&cdm->fd_counters, 0x5555); | 
 | 245 |  | 
 | 246 | 	/* Configure the XLB Arbiter priorities */ | 
 | 247 | 	out_be32(&xlb->master_pri_enable, 0xff); | 
 | 248 | 	out_be32(&xlb->master_priority, 0x11111111); | 
 | 249 |  | 
 | 250 | 	/* Enable ram snooping for 1GB window */ | 
 | 251 | 	out_be32(&xlb->config, in_be32(&xlb->config) | MPC52xx_XLB_CFG_SNOOP); | 
 | 252 | 	out_be32(&xlb->snoop_window, MPC52xx_PCI_TARGET_MEM | 0x1d); | 
 | 253 |  | 
 | 254 | 	/* Disable XLB pipelining */ | 
 | 255 | 	/* (cfr errate 292. We could do this only just before ATA PIO | 
 | 256 | 	    transaction and re-enable it after ...) */ | 
 | 257 | 	out_be32(&xlb->config, in_be32(&xlb->config) | MPC52xx_XLB_CFG_PLDIS); | 
 | 258 |  | 
 | 259 | 	/* Unmap reg zone */ | 
 | 260 | unmap_regs: | 
 | 261 | 	if (cdm)  iounmap(cdm); | 
 | 262 | 	if (xlb)  iounmap(xlb); | 
 | 263 | } | 
 | 264 |  | 
 | 265 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 266 | int mpc52xx_match_psc_function(int psc_idx, const char *func) | 
 | 267 | { | 
 | 268 | 	struct mpc52xx_psc_func *cf = mpc52xx_psc_functions; | 
 | 269 |  | 
 | 270 | 	while ((cf->id != -1) && (cf->func != NULL)) { | 
 | 271 | 		if ((cf->id == psc_idx) && !strcmp(cf->func,func)) | 
 | 272 | 			return 1; | 
 | 273 | 		cf++; | 
 | 274 | 	} | 
 | 275 |  | 
 | 276 | 	return 0; | 
 | 277 | } |