common.c 10.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * arch/arm/mach-mv78xx0/common.c
 *
 * Core functions for Marvell MV78xx0 SoCs
 *
 * 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/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
#include <linux/ata_platform.h>
16
#include <linux/ethtool.h>
17 18
#include <asm/mach/map.h>
#include <asm/mach/time.h>
19
#include <mach/mv78xx0.h>
20
#include <mach/bridge-regs.h>
21
#include <plat/cache-feroceon-l2.h>
22
#include <plat/ehci-orion.h>
23 24
#include <plat/orion_nand.h>
#include <plat/time.h>
25
#include <plat/common.h>
26
#include <plat/addr-map.h>
27 28
#include "common.h"

29
static int get_tclk(void);
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172

/*****************************************************************************
 * Common bits
 ****************************************************************************/
int mv78xx0_core_index(void)
{
	u32 extra;

	/*
	 * Read Extra Features register.
	 */
	__asm__("mrc p15, 1, %0, c15, c1, 0" : "=r" (extra));

	return !!(extra & 0x00004000);
}

static int get_hclk(void)
{
	int hclk;

	/*
	 * HCLK tick rate is configured by DEV_D[7:5] pins.
	 */
	switch ((readl(SAMPLE_AT_RESET_LOW) >> 5) & 7) {
	case 0:
		hclk = 166666667;
		break;
	case 1:
		hclk = 200000000;
		break;
	case 2:
		hclk = 266666667;
		break;
	case 3:
		hclk = 333333333;
		break;
	case 4:
		hclk = 400000000;
		break;
	default:
		panic("unknown HCLK PLL setting: %.8x\n",
			readl(SAMPLE_AT_RESET_LOW));
	}

	return hclk;
}

static void get_pclk_l2clk(int hclk, int core_index, int *pclk, int *l2clk)
{
	u32 cfg;

	/*
	 * Core #0 PCLK/L2CLK is configured by bits [13:8], core #1
	 * PCLK/L2CLK by bits [19:14].
	 */
	if (core_index == 0) {
		cfg = (readl(SAMPLE_AT_RESET_LOW) >> 8) & 0x3f;
	} else {
		cfg = (readl(SAMPLE_AT_RESET_LOW) >> 14) & 0x3f;
	}

	/*
	 * Bits [11:8] ([17:14] for core #1) configure the PCLK:HCLK
	 * ratio (1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6).
	 */
	*pclk = ((u64)hclk * (2 + (cfg & 0xf))) >> 1;

	/*
	 * Bits [13:12] ([19:18] for core #1) configure the PCLK:L2CLK
	 * ratio (1, 2, 3).
	 */
	*l2clk = *pclk / (((cfg >> 4) & 3) + 1);
}

static int get_tclk(void)
{
	int tclk;

	/*
	 * TCLK tick rate is configured by DEV_A[2:0] strap pins.
	 */
	switch ((readl(SAMPLE_AT_RESET_HIGH) >> 6) & 7) {
	case 1:
		tclk = 166666667;
		break;
	case 3:
		tclk = 200000000;
		break;
	default:
		panic("unknown TCLK PLL setting: %.8x\n",
			readl(SAMPLE_AT_RESET_HIGH));
	}

	return tclk;
}


/*****************************************************************************
 * I/O Address Mapping
 ****************************************************************************/
static struct map_desc mv78xx0_io_desc[] __initdata = {
	{
		.virtual	= MV78XX0_CORE_REGS_VIRT_BASE,
		.pfn		= 0,
		.length		= MV78XX0_CORE_REGS_SIZE,
		.type		= MT_DEVICE,
	}, {
		.virtual	= MV78XX0_PCIE_IO_VIRT_BASE(0),
		.pfn		= __phys_to_pfn(MV78XX0_PCIE_IO_PHYS_BASE(0)),
		.length		= MV78XX0_PCIE_IO_SIZE * 8,
		.type		= MT_DEVICE,
	}, {
		.virtual	= MV78XX0_REGS_VIRT_BASE,
		.pfn		= __phys_to_pfn(MV78XX0_REGS_PHYS_BASE),
		.length		= MV78XX0_REGS_SIZE,
		.type		= MT_DEVICE,
	},
};

void __init mv78xx0_map_io(void)
{
	unsigned long phys;

	/*
	 * Map the right set of per-core registers depending on
	 * which core we are running on.
	 */
	if (mv78xx0_core_index() == 0) {
		phys = MV78XX0_CORE0_REGS_PHYS_BASE;
	} else {
		phys = MV78XX0_CORE1_REGS_PHYS_BASE;
	}
	mv78xx0_io_desc[0].pfn = __phys_to_pfn(phys);

	iotable_init(mv78xx0_io_desc, ARRAY_SIZE(mv78xx0_io_desc));
}


/*****************************************************************************
 * EHCI
 ****************************************************************************/
void __init mv78xx0_ehci0_init(void)
{
173
	orion_ehci_init(USB0_PHYS_BASE, IRQ_MV78XX0_USB_0, EHCI_PHY_NA);
174 175 176 177 178 179 180 181
}


/*****************************************************************************
 * EHCI1
 ****************************************************************************/
void __init mv78xx0_ehci1_init(void)
{
182
	orion_ehci_1_init(USB1_PHYS_BASE, IRQ_MV78XX0_USB_1);
183 184 185 186 187 188 189 190
}


/*****************************************************************************
 * EHCI2
 ****************************************************************************/
void __init mv78xx0_ehci2_init(void)
{
191
	orion_ehci_2_init(USB2_PHYS_BASE, IRQ_MV78XX0_USB_2);
192 193 194 195 196 197 198 199
}


/*****************************************************************************
 * GE00
 ****************************************************************************/
void __init mv78xx0_ge00_init(struct mv643xx_eth_platform_data *eth_data)
{
200
	orion_ge00_init(eth_data,
201 202
			GE00_PHYS_BASE, IRQ_MV78XX0_GE00_SUM,
			IRQ_MV78XX0_GE_ERR, get_tclk());
203 204 205 206 207 208 209 210
}


/*****************************************************************************
 * GE01
 ****************************************************************************/
void __init mv78xx0_ge01_init(struct mv643xx_eth_platform_data *eth_data)
{
211
	orion_ge01_init(eth_data,
212 213
			GE01_PHYS_BASE, IRQ_MV78XX0_GE01_SUM,
			NO_IRQ, get_tclk());
214 215 216 217 218 219 220 221
}


/*****************************************************************************
 * GE10
 ****************************************************************************/
void __init mv78xx0_ge10_init(struct mv643xx_eth_platform_data *eth_data)
{
222 223 224 225 226 227 228 229 230 231 232 233 234
	u32 dev, rev;

	/*
	 * On the Z0, ge10 and ge11 are internally connected back
	 * to back, and not brought out.
	 */
	mv78xx0_pcie_id(&dev, &rev);
	if (dev == MV78X00_Z0_DEV_ID) {
		eth_data->phy_addr = MV643XX_ETH_PHY_NONE;
		eth_data->speed = SPEED_1000;
		eth_data->duplex = DUPLEX_FULL;
	}

235
	orion_ge10_init(eth_data,
236 237
			GE10_PHYS_BASE, IRQ_MV78XX0_GE10_SUM,
			NO_IRQ, get_tclk());
238 239 240 241 242 243 244 245
}


/*****************************************************************************
 * GE11
 ****************************************************************************/
void __init mv78xx0_ge11_init(struct mv643xx_eth_platform_data *eth_data)
{
246 247 248 249 250 251 252 253 254 255 256 257 258
	u32 dev, rev;

	/*
	 * On the Z0, ge10 and ge11 are internally connected back
	 * to back, and not brought out.
	 */
	mv78xx0_pcie_id(&dev, &rev);
	if (dev == MV78X00_Z0_DEV_ID) {
		eth_data->phy_addr = MV643XX_ETH_PHY_NONE;
		eth_data->speed = SPEED_1000;
		eth_data->duplex = DUPLEX_FULL;
	}

259
	orion_ge11_init(eth_data,
260 261
			GE11_PHYS_BASE, IRQ_MV78XX0_GE11_SUM,
			NO_IRQ, get_tclk());
262 263
}

R
Riku Voipio 已提交
264
/*****************************************************************************
265
 * I2C
R
Riku Voipio 已提交
266 267 268
 ****************************************************************************/
void __init mv78xx0_i2c_init(void)
{
269 270
	orion_i2c_init(I2C_0_PHYS_BASE, IRQ_MV78XX0_I2C_0, 8);
	orion_i2c_1_init(I2C_1_PHYS_BASE, IRQ_MV78XX0_I2C_1, 8);
R
Riku Voipio 已提交
271
}
272 273 274 275 276 277

/*****************************************************************************
 * SATA
 ****************************************************************************/
void __init mv78xx0_sata_init(struct mv_sata_platform_data *sata_data)
{
278
	orion_sata_init(sata_data, SATA_PHYS_BASE, IRQ_MV78XX0_SATA);
279 280 281 282 283 284 285 286
}


/*****************************************************************************
 * UART0
 ****************************************************************************/
void __init mv78xx0_uart0_init(void)
{
287 288
	orion_uart0_init(UART0_VIRT_BASE, UART0_PHYS_BASE,
			 IRQ_MV78XX0_UART_0, get_tclk());
289 290 291 292 293 294 295 296
}


/*****************************************************************************
 * UART1
 ****************************************************************************/
void __init mv78xx0_uart1_init(void)
{
297 298
	orion_uart1_init(UART1_VIRT_BASE, UART1_PHYS_BASE,
			 IRQ_MV78XX0_UART_1, get_tclk());
299 300 301 302 303 304 305 306
}


/*****************************************************************************
 * UART2
 ****************************************************************************/
void __init mv78xx0_uart2_init(void)
{
307 308
	orion_uart2_init(UART2_VIRT_BASE, UART2_PHYS_BASE,
			 IRQ_MV78XX0_UART_2, get_tclk());
309 310 311 312 313 314 315
}

/*****************************************************************************
 * UART3
 ****************************************************************************/
void __init mv78xx0_uart3_init(void)
{
316 317
	orion_uart3_init(UART3_VIRT_BASE, UART3_PHYS_BASE,
			 IRQ_MV78XX0_UART_3, get_tclk());
318 319 320 321 322
}

/*****************************************************************************
 * Time handling
 ****************************************************************************/
323 324 325 326 327
void __init mv78xx0_init_early(void)
{
	orion_time_set_base(TIMER_VIRT_BASE);
}

328 329
static void mv78xx0_timer_init(void)
{
330 331
	orion_time_init(BRIDGE_VIRT_BASE, BRIDGE_INT_TIMER1_CLR,
			IRQ_MV78XX0_TIMER_1, get_tclk());
332 333 334 335 336 337 338 339 340 341
}

struct sys_timer mv78xx0_timer = {
	.init = mv78xx0_timer_init,
};


/*****************************************************************************
 * General
 ****************************************************************************/
342 343 344 345 346 347 348 349 350 351 352 353 354 355
static char * __init mv78xx0_id(void)
{
	u32 dev, rev;

	mv78xx0_pcie_id(&dev, &rev);

	if (dev == MV78X00_Z0_DEV_ID) {
		if (rev == MV78X00_REV_Z0)
			return "MV78X00-Z0";
		else
			return "MV78X00-Rev-Unsupported";
	} else if (dev == MV78100_DEV_ID) {
		if (rev == MV78100_REV_A0)
			return "MV78100-A0";
356 357
		else if (rev == MV78100_REV_A1)
			return "MV78100-A1";
358 359 360 361 362 363 364 365 366 367 368 369
		else
			return "MV78100-Rev-Unsupported";
	} else if (dev == MV78200_DEV_ID) {
		if (rev == MV78100_REV_A0)
			return "MV78200-A0";
		else
			return "MV78200-Rev-Unsupported";
	} else {
		return "Device-Unknown";
	}
}

370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
static int __init is_l2_writethrough(void)
{
	return !!(readl(CPU_CONTROL) & L2_WRITETHROUGH);
}

void __init mv78xx0_init(void)
{
	int core_index;
	int hclk;
	int pclk;
	int l2clk;
	int tclk;

	core_index = mv78xx0_core_index();
	hclk = get_hclk();
	get_pclk_l2clk(hclk, core_index, &pclk, &l2clk);
	tclk = get_tclk();

388 389
	printk(KERN_INFO "%s ", mv78xx0_id());
	printk("core #%d, ", core_index);
390 391 392 393 394 395 396 397 398 399 400
	printk("PCLK = %dMHz, ", (pclk + 499999) / 1000000);
	printk("L2 = %dMHz, ", (l2clk + 499999) / 1000000);
	printk("HCLK = %dMHz, ", (hclk + 499999) / 1000000);
	printk("TCLK = %dMHz\n", (tclk + 499999) / 1000000);

	mv78xx0_setup_cpu_mbus();

#ifdef CONFIG_CACHE_FEROCEON_L2
	feroceon_l2_init(is_l2_writethrough());
#endif
}
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416

void mv78xx0_restart(char mode, const char *cmd)
{
	/*
	 * Enable soft reset to assert RSTOUTn.
	 */
	writel(SOFT_RESET_OUT_EN, RSTOUTn_MASK);

	/*
	 * Assert soft reset.
	 */
	writel(SOFT_RESET, SYSTEM_SOFT_RESET);

	while (1)
		;
}