PageRenderTime 27ms CodeModel.GetById 12ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 0ms

/arch/arm/mach-mv78xx0/common.c

https://github.com/AICP/kernel_asus_grouper
C | 403 lines | 250 code | 60 blank | 93 comment | 30 complexity | 895dfad4891bdac2998aa040a7d7e267 MD5 | raw file
  1/*
  2 * arch/arm/mach-mv78xx0/common.c
  3 *
  4 * Core functions for Marvell MV78xx0 SoCs
  5 *
  6 * This file is licensed under the terms of the GNU General Public
  7 * License version 2.  This program is licensed "as is" without any
  8 * warranty of any kind, whether express or implied.
  9 */
 10
 11#include <linux/kernel.h>
 12#include <linux/init.h>
 13#include <linux/platform_device.h>
 14#include <linux/serial_8250.h>
 15#include <linux/mbus.h>
 16#include <linux/ata_platform.h>
 17#include <linux/ethtool.h>
 18#include <asm/mach/map.h>
 19#include <asm/mach/time.h>
 20#include <mach/mv78xx0.h>
 21#include <mach/bridge-regs.h>
 22#include <plat/cache-feroceon-l2.h>
 23#include <plat/orion_nand.h>
 24#include <plat/time.h>
 25#include <plat/common.h>
 26#include "common.h"
 27
 28static int get_tclk(void);
 29
 30/*****************************************************************************
 31 * Common bits
 32 ****************************************************************************/
 33int mv78xx0_core_index(void)
 34{
 35	u32 extra;
 36
 37	/*
 38	 * Read Extra Features register.
 39	 */
 40	__asm__("mrc p15, 1, %0, c15, c1, 0" : "=r" (extra));
 41
 42	return !!(extra & 0x00004000);
 43}
 44
 45static int get_hclk(void)
 46{
 47	int hclk;
 48
 49	/*
 50	 * HCLK tick rate is configured by DEV_D[7:5] pins.
 51	 */
 52	switch ((readl(SAMPLE_AT_RESET_LOW) >> 5) & 7) {
 53	case 0:
 54		hclk = 166666667;
 55		break;
 56	case 1:
 57		hclk = 200000000;
 58		break;
 59	case 2:
 60		hclk = 266666667;
 61		break;
 62	case 3:
 63		hclk = 333333333;
 64		break;
 65	case 4:
 66		hclk = 400000000;
 67		break;
 68	default:
 69		panic("unknown HCLK PLL setting: %.8x\n",
 70			readl(SAMPLE_AT_RESET_LOW));
 71	}
 72
 73	return hclk;
 74}
 75
 76static void get_pclk_l2clk(int hclk, int core_index, int *pclk, int *l2clk)
 77{
 78	u32 cfg;
 79
 80	/*
 81	 * Core #0 PCLK/L2CLK is configured by bits [13:8], core #1
 82	 * PCLK/L2CLK by bits [19:14].
 83	 */
 84	if (core_index == 0) {
 85		cfg = (readl(SAMPLE_AT_RESET_LOW) >> 8) & 0x3f;
 86	} else {
 87		cfg = (readl(SAMPLE_AT_RESET_LOW) >> 14) & 0x3f;
 88	}
 89
 90	/*
 91	 * Bits [11:8] ([17:14] for core #1) configure the PCLK:HCLK
 92	 * ratio (1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6).
 93	 */
 94	*pclk = ((u64)hclk * (2 + (cfg & 0xf))) >> 1;
 95
 96	/*
 97	 * Bits [13:12] ([19:18] for core #1) configure the PCLK:L2CLK
 98	 * ratio (1, 2, 3).
 99	 */
100	*l2clk = *pclk / (((cfg >> 4) & 3) + 1);
101}
102
103static int get_tclk(void)
104{
105	int tclk;
106
107	/*
108	 * TCLK tick rate is configured by DEV_A[2:0] strap pins.
109	 */
110	switch ((readl(SAMPLE_AT_RESET_HIGH) >> 6) & 7) {
111	case 1:
112		tclk = 166666667;
113		break;
114	case 3:
115		tclk = 200000000;
116		break;
117	default:
118		panic("unknown TCLK PLL setting: %.8x\n",
119			readl(SAMPLE_AT_RESET_HIGH));
120	}
121
122	return tclk;
123}
124
125
126/*****************************************************************************
127 * I/O Address Mapping
128 ****************************************************************************/
129static struct map_desc mv78xx0_io_desc[] __initdata = {
130	{
131		.virtual	= MV78XX0_CORE_REGS_VIRT_BASE,
132		.pfn		= 0,
133		.length		= MV78XX0_CORE_REGS_SIZE,
134		.type		= MT_DEVICE,
135	}, {
136		.virtual	= MV78XX0_PCIE_IO_VIRT_BASE(0),
137		.pfn		= __phys_to_pfn(MV78XX0_PCIE_IO_PHYS_BASE(0)),
138		.length		= MV78XX0_PCIE_IO_SIZE * 8,
139		.type		= MT_DEVICE,
140	}, {
141		.virtual	= MV78XX0_REGS_VIRT_BASE,
142		.pfn		= __phys_to_pfn(MV78XX0_REGS_PHYS_BASE),
143		.length		= MV78XX0_REGS_SIZE,
144		.type		= MT_DEVICE,
145	},
146};
147
148void __init mv78xx0_map_io(void)
149{
150	unsigned long phys;
151
152	/*
153	 * Map the right set of per-core registers depending on
154	 * which core we are running on.
155	 */
156	if (mv78xx0_core_index() == 0) {
157		phys = MV78XX0_CORE0_REGS_PHYS_BASE;
158	} else {
159		phys = MV78XX0_CORE1_REGS_PHYS_BASE;
160	}
161	mv78xx0_io_desc[0].pfn = __phys_to_pfn(phys);
162
163	iotable_init(mv78xx0_io_desc, ARRAY_SIZE(mv78xx0_io_desc));
164}
165
166
167/*****************************************************************************
168 * EHCI
169 ****************************************************************************/
170void __init mv78xx0_ehci0_init(void)
171{
172	orion_ehci_init(&mv78xx0_mbus_dram_info,
173			USB0_PHYS_BASE, IRQ_MV78XX0_USB_0);
174}
175
176
177/*****************************************************************************
178 * EHCI1
179 ****************************************************************************/
180void __init mv78xx0_ehci1_init(void)
181{
182	orion_ehci_1_init(&mv78xx0_mbus_dram_info,
183			  USB1_PHYS_BASE, IRQ_MV78XX0_USB_1);
184}
185
186
187/*****************************************************************************
188 * EHCI2
189 ****************************************************************************/
190void __init mv78xx0_ehci2_init(void)
191{
192	orion_ehci_2_init(&mv78xx0_mbus_dram_info,
193			  USB2_PHYS_BASE, IRQ_MV78XX0_USB_2);
194}
195
196
197/*****************************************************************************
198 * GE00
199 ****************************************************************************/
200void __init mv78xx0_ge00_init(struct mv643xx_eth_platform_data *eth_data)
201{
202	orion_ge00_init(eth_data, &mv78xx0_mbus_dram_info,
203			GE00_PHYS_BASE, IRQ_MV78XX0_GE00_SUM,
204			IRQ_MV78XX0_GE_ERR, get_tclk());
205}
206
207
208/*****************************************************************************
209 * GE01
210 ****************************************************************************/
211void __init mv78xx0_ge01_init(struct mv643xx_eth_platform_data *eth_data)
212{
213	orion_ge01_init(eth_data, &mv78xx0_mbus_dram_info,
214			GE01_PHYS_BASE, IRQ_MV78XX0_GE01_SUM,
215			NO_IRQ, get_tclk());
216}
217
218
219/*****************************************************************************
220 * GE10
221 ****************************************************************************/
222void __init mv78xx0_ge10_init(struct mv643xx_eth_platform_data *eth_data)
223{
224	u32 dev, rev;
225
226	/*
227	 * On the Z0, ge10 and ge11 are internally connected back
228	 * to back, and not brought out.
229	 */
230	mv78xx0_pcie_id(&dev, &rev);
231	if (dev == MV78X00_Z0_DEV_ID) {
232		eth_data->phy_addr = MV643XX_ETH_PHY_NONE;
233		eth_data->speed = SPEED_1000;
234		eth_data->duplex = DUPLEX_FULL;
235	}
236
237	orion_ge10_init(eth_data, &mv78xx0_mbus_dram_info,
238			GE10_PHYS_BASE, IRQ_MV78XX0_GE10_SUM,
239			NO_IRQ, get_tclk());
240}
241
242
243/*****************************************************************************
244 * GE11
245 ****************************************************************************/
246void __init mv78xx0_ge11_init(struct mv643xx_eth_platform_data *eth_data)
247{
248	u32 dev, rev;
249
250	/*
251	 * On the Z0, ge10 and ge11 are internally connected back
252	 * to back, and not brought out.
253	 */
254	mv78xx0_pcie_id(&dev, &rev);
255	if (dev == MV78X00_Z0_DEV_ID) {
256		eth_data->phy_addr = MV643XX_ETH_PHY_NONE;
257		eth_data->speed = SPEED_1000;
258		eth_data->duplex = DUPLEX_FULL;
259	}
260
261	orion_ge11_init(eth_data, &mv78xx0_mbus_dram_info,
262			GE11_PHYS_BASE, IRQ_MV78XX0_GE11_SUM,
263			NO_IRQ, get_tclk());
264}
265
266/*****************************************************************************
267 * I2C
268 ****************************************************************************/
269void __init mv78xx0_i2c_init(void)
270{
271	orion_i2c_init(I2C_0_PHYS_BASE, IRQ_MV78XX0_I2C_0, 8);
272	orion_i2c_1_init(I2C_1_PHYS_BASE, IRQ_MV78XX0_I2C_1, 8);
273}
274
275/*****************************************************************************
276 * SATA
277 ****************************************************************************/
278void __init mv78xx0_sata_init(struct mv_sata_platform_data *sata_data)
279{
280	orion_sata_init(sata_data, &mv78xx0_mbus_dram_info,
281			SATA_PHYS_BASE, IRQ_MV78XX0_SATA);
282}
283
284
285/*****************************************************************************
286 * UART0
287 ****************************************************************************/
288void __init mv78xx0_uart0_init(void)
289{
290	orion_uart0_init(UART0_VIRT_BASE, UART0_PHYS_BASE,
291			 IRQ_MV78XX0_UART_0, get_tclk());
292}
293
294
295/*****************************************************************************
296 * UART1
297 ****************************************************************************/
298void __init mv78xx0_uart1_init(void)
299{
300	orion_uart1_init(UART1_VIRT_BASE, UART1_PHYS_BASE,
301			 IRQ_MV78XX0_UART_1, get_tclk());
302}
303
304
305/*****************************************************************************
306 * UART2
307 ****************************************************************************/
308void __init mv78xx0_uart2_init(void)
309{
310	orion_uart2_init(UART2_VIRT_BASE, UART2_PHYS_BASE,
311			 IRQ_MV78XX0_UART_2, get_tclk());
312}
313
314/*****************************************************************************
315 * UART3
316 ****************************************************************************/
317void __init mv78xx0_uart3_init(void)
318{
319	orion_uart3_init(UART3_VIRT_BASE, UART3_PHYS_BASE,
320			 IRQ_MV78XX0_UART_3, get_tclk());
321}
322
323/*****************************************************************************
324 * Time handling
325 ****************************************************************************/
326void __init mv78xx0_init_early(void)
327{
328	orion_time_set_base(TIMER_VIRT_BASE);
329}
330
331static void mv78xx0_timer_init(void)
332{
333	orion_time_init(BRIDGE_VIRT_BASE, BRIDGE_INT_TIMER1_CLR,
334			IRQ_MV78XX0_TIMER_1, get_tclk());
335}
336
337struct sys_timer mv78xx0_timer = {
338	.init = mv78xx0_timer_init,
339};
340
341
342/*****************************************************************************
343 * General
344 ****************************************************************************/
345static char * __init mv78xx0_id(void)
346{
347	u32 dev, rev;
348
349	mv78xx0_pcie_id(&dev, &rev);
350
351	if (dev == MV78X00_Z0_DEV_ID) {
352		if (rev == MV78X00_REV_Z0)
353			return "MV78X00-Z0";
354		else
355			return "MV78X00-Rev-Unsupported";
356	} else if (dev == MV78100_DEV_ID) {
357		if (rev == MV78100_REV_A0)
358			return "MV78100-A0";
359		else if (rev == MV78100_REV_A1)
360			return "MV78100-A1";
361		else
362			return "MV78100-Rev-Unsupported";
363	} else if (dev == MV78200_DEV_ID) {
364		if (rev == MV78100_REV_A0)
365			return "MV78200-A0";
366		else
367			return "MV78200-Rev-Unsupported";
368	} else {
369		return "Device-Unknown";
370	}
371}
372
373static int __init is_l2_writethrough(void)
374{
375	return !!(readl(CPU_CONTROL) & L2_WRITETHROUGH);
376}
377
378void __init mv78xx0_init(void)
379{
380	int core_index;
381	int hclk;
382	int pclk;
383	int l2clk;
384	int tclk;
385
386	core_index = mv78xx0_core_index();
387	hclk = get_hclk();
388	get_pclk_l2clk(hclk, core_index, &pclk, &l2clk);
389	tclk = get_tclk();
390
391	printk(KERN_INFO "%s ", mv78xx0_id());
392	printk("core #%d, ", core_index);
393	printk("PCLK = %dMHz, ", (pclk + 499999) / 1000000);
394	printk("L2 = %dMHz, ", (l2clk + 499999) / 1000000);
395	printk("HCLK = %dMHz, ", (hclk + 499999) / 1000000);
396	printk("TCLK = %dMHz\n", (tclk + 499999) / 1000000);
397
398	mv78xx0_setup_cpu_mbus();
399
400#ifdef CONFIG_CACHE_FEROCEON_L2
401	feroceon_l2_init(is_l2_writethrough());
402#endif
403}