diff options
author | Arnd Bergmann <arnd@arndb.de> | 2013-03-14 17:27:32 -0400 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2013-03-14 17:30:21 -0400 |
commit | 415f59142d9d9dd023deaeb3b4dfc1aecdd3983c (patch) | |
tree | 3d74c3a5b87dea625ca328897751c3253594ae68 | |
parent | 15bc1fe67f66644c8093cc2d3304217d1c7de797 (diff) |
ARM: cns3xxx: initial DT support
This adds very minimal support for booting cns3xxx using a device
tree. It should support the same devices that cns3420vb provides
but gets them from the DT. All devices that don't have their own
binding are probed through auxdata. This is completely untested
and likely incomplete.
Booting through ATAGS is made optional, so it can be turned off
by anybody who has a DTB file.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
-rw-r--r-- | arch/arm/mach-cns3xxx/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-cns3xxx/Makefile | 8 | ||||
-rw-r--r-- | arch/arm/mach-cns3xxx/core.c | 119 |
3 files changed, 125 insertions, 3 deletions
diff --git a/arch/arm/mach-cns3xxx/Kconfig b/arch/arm/mach-cns3xxx/Kconfig index 5720f3df1af2..dbf0df8bb0ac 100644 --- a/arch/arm/mach-cns3xxx/Kconfig +++ b/arch/arm/mach-cns3xxx/Kconfig | |||
@@ -14,6 +14,7 @@ menu "CNS3XXX platform type" | |||
14 | 14 | ||
15 | config MACH_CNS3420VB | 15 | config MACH_CNS3420VB |
16 | bool "Support for CNS3420 Validation Board" | 16 | bool "Support for CNS3420 Validation Board" |
17 | depends on ATAGS | ||
17 | help | 18 | help |
18 | Include support for the Cavium Networks CNS3420 MPCore Platform | 19 | Include support for the Cavium Networks CNS3420 MPCore Platform |
19 | Baseboard. | 20 | Baseboard. |
diff --git a/arch/arm/mach-cns3xxx/Makefile b/arch/arm/mach-cns3xxx/Makefile index 11033f1c2e23..a1ff10848698 100644 --- a/arch/arm/mach-cns3xxx/Makefile +++ b/arch/arm/mach-cns3xxx/Makefile | |||
@@ -1,3 +1,5 @@ | |||
1 | obj-$(CONFIG_ARCH_CNS3XXX) += core.o pm.o devices.o | 1 | obj-$(CONFIG_ARCH_CNS3XXX) += cns3xxx.o |
2 | obj-$(CONFIG_PCI) += pcie.o | 2 | cns3xxx-y += core.o pm.o |
3 | obj-$(CONFIG_MACH_CNS3420VB) += cns3420vb.o | 3 | cns3xxx-$(CONFIG_ATAGS) += devices.o |
4 | cns3xxx-$(CONFIG_PCI) += pcie.o | ||
5 | cns3xxx-$(CONFIG_MACH_CNS3420VB) += cns3420vb.o | ||
diff --git a/arch/arm/mach-cns3xxx/core.c b/arch/arm/mach-cns3xxx/core.c index 012ffdb9e142..49e657c15067 100644 --- a/arch/arm/mach-cns3xxx/core.c +++ b/arch/arm/mach-cns3xxx/core.c | |||
@@ -13,12 +13,18 @@ | |||
13 | #include <linux/clockchips.h> | 13 | #include <linux/clockchips.h> |
14 | #include <linux/io.h> | 14 | #include <linux/io.h> |
15 | #include <linux/irqchip/arm-gic.h> | 15 | #include <linux/irqchip/arm-gic.h> |
16 | #include <linux/of_platform.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/usb/ehci_pdriver.h> | ||
19 | #include <linux/usb/ohci_pdriver.h> | ||
20 | #include <asm/mach/arch.h> | ||
16 | #include <asm/mach/map.h> | 21 | #include <asm/mach/map.h> |
17 | #include <asm/mach/time.h> | 22 | #include <asm/mach/time.h> |
18 | #include <asm/mach/irq.h> | 23 | #include <asm/mach/irq.h> |
19 | #include <asm/hardware/cache-l2x0.h> | 24 | #include <asm/hardware/cache-l2x0.h> |
20 | #include "cns3xxx.h" | 25 | #include "cns3xxx.h" |
21 | #include "core.h" | 26 | #include "core.h" |
27 | #include "pm.h" | ||
22 | 28 | ||
23 | static struct map_desc cns3xxx_io_desc[] __initdata = { | 29 | static struct map_desc cns3xxx_io_desc[] __initdata = { |
24 | { | 30 | { |
@@ -276,3 +282,116 @@ void __init cns3xxx_l2x0_init(void) | |||
276 | } | 282 | } |
277 | 283 | ||
278 | #endif /* CONFIG_CACHE_L2X0 */ | 284 | #endif /* CONFIG_CACHE_L2X0 */ |
285 | |||
286 | static int csn3xxx_usb_power_on(struct platform_device *pdev) | ||
287 | { | ||
288 | /* | ||
289 | * EHCI and OHCI share the same clock and power, | ||
290 | * resetting twice would cause the 1st controller been reset. | ||
291 | * Therefore only do power up at the first up device, and | ||
292 | * power down at the last down device. | ||
293 | * | ||
294 | * Set USB AHB INCR length to 16 | ||
295 | */ | ||
296 | if (atomic_inc_return(&usb_pwr_ref) == 1) { | ||
297 | cns3xxx_pwr_power_up(1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_PLL_USB); | ||
298 | cns3xxx_pwr_clk_en(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); | ||
299 | cns3xxx_pwr_soft_rst(1 << PM_SOFT_RST_REG_OFFST_USB_HOST); | ||
300 | __raw_writel((__raw_readl(MISC_CHIP_CONFIG_REG) | (0X2 << 24)), | ||
301 | MISC_CHIP_CONFIG_REG); | ||
302 | } | ||
303 | |||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | static void csn3xxx_usb_power_off(struct platform_device *pdev) | ||
308 | { | ||
309 | /* | ||
310 | * EHCI and OHCI share the same clock and power, | ||
311 | * resetting twice would cause the 1st controller been reset. | ||
312 | * Therefore only do power up at the first up device, and | ||
313 | * power down at the last down device. | ||
314 | */ | ||
315 | if (atomic_dec_return(&usb_pwr_ref) == 0) | ||
316 | cns3xxx_pwr_clk_dis(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); | ||
317 | } | ||
318 | |||
319 | static struct usb_ehci_pdata cns3xxx_usb_ehci_pdata = { | ||
320 | .power_on = csn3xxx_usb_power_on, | ||
321 | .power_off = csn3xxx_usb_power_off, | ||
322 | }; | ||
323 | |||
324 | static struct usb_ohci_pdata cns3xxx_usb_ohci_pdata = { | ||
325 | .num_ports = 1, | ||
326 | .power_on = csn3xxx_usb_power_on, | ||
327 | .power_off = csn3xxx_usb_power_off, | ||
328 | }; | ||
329 | |||
330 | static struct of_dev_auxdata cns3xxx_auxdata[] __initconst = { | ||
331 | { "intel,usb-ehci", CNS3XXX_USB_BASE, "ehci-platform", &cns3xxx_usb_ehci_pdata }, | ||
332 | { "intel,usb-ohci", CNS3XXX_USB_OHCI_BASE, "ohci-platform", &cns3xxx_usb_ohci_pdata }, | ||
333 | { "cavium,cns3420-ahci", CNS3XXX_SATA2_BASE, "ahci", NULL }, | ||
334 | { "cavium,cns3420-sdhci", CNS3XXX_SDIO_BASE, "ahci", NULL }, | ||
335 | {}, | ||
336 | }; | ||
337 | |||
338 | static void __init cns3xxx_init(void) | ||
339 | { | ||
340 | struct device_node *dn; | ||
341 | |||
342 | cns3xxx_l2x0_init(); | ||
343 | |||
344 | dn = of_find_compatible_node(NULL, NULL, "cavium,cns3420-ahci"); | ||
345 | if (of_device_is_available(dn)) { | ||
346 | u32 tmp; | ||
347 | |||
348 | tmp = __raw_readl(MISC_SATA_POWER_MODE); | ||
349 | tmp |= 0x1 << 16; /* Disable SATA PHY 0 from SLUMBER Mode */ | ||
350 | tmp |= 0x1 << 17; /* Disable SATA PHY 1 from SLUMBER Mode */ | ||
351 | __raw_writel(tmp, MISC_SATA_POWER_MODE); | ||
352 | |||
353 | /* Enable SATA PHY */ | ||
354 | cns3xxx_pwr_power_up(0x1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_SATA_PHY0); | ||
355 | cns3xxx_pwr_power_up(0x1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_SATA_PHY1); | ||
356 | |||
357 | /* Enable SATA Clock */ | ||
358 | cns3xxx_pwr_clk_en(0x1 << PM_CLK_GATE_REG_OFFSET_SATA); | ||
359 | |||
360 | /* De-Asscer SATA Reset */ | ||
361 | cns3xxx_pwr_soft_rst(CNS3XXX_PWR_SOFTWARE_RST(SATA)); | ||
362 | } | ||
363 | |||
364 | dn = of_find_compatible_node(NULL, NULL, "cavium,cns3420-sdhci"); | ||
365 | if (of_device_is_available(dn)) { | ||
366 | u32 __iomem *gpioa = IOMEM(CNS3XXX_MISC_BASE_VIRT + 0x0014); | ||
367 | u32 gpioa_pins = __raw_readl(gpioa); | ||
368 | |||
369 | /* MMC/SD pins share with GPIOA */ | ||
370 | gpioa_pins |= 0x1fff0004; | ||
371 | __raw_writel(gpioa_pins, gpioa); | ||
372 | |||
373 | cns3xxx_pwr_clk_en(CNS3XXX_PWR_CLK_EN(SDIO)); | ||
374 | cns3xxx_pwr_soft_rst(CNS3XXX_PWR_SOFTWARE_RST(SDIO)); | ||
375 | } | ||
376 | |||
377 | pm_power_off = cns3xxx_power_off; | ||
378 | |||
379 | of_platform_populate(NULL, of_default_bus_match_table, | ||
380 | cns3xxx_auxdata, NULL); | ||
381 | } | ||
382 | |||
383 | static const char *cns3xxx_dt_compat[] __initdata = { | ||
384 | "cavium,cns3410", | ||
385 | "cavium,cns3420", | ||
386 | NULL, | ||
387 | }; | ||
388 | |||
389 | DT_MACHINE_START(CNS3XXX_DT, "Cavium Networks CNS3xxx") | ||
390 | .dt_compat = cns3xxx_dt_compat, | ||
391 | .nr_irqs = NR_IRQS_CNS3XXX, | ||
392 | .map_io = cns3xxx_map_io, | ||
393 | .init_irq = cns3xxx_init_irq, | ||
394 | .init_time = cns3xxx_timer_init, | ||
395 | .init_machine = cns3xxx_init, | ||
396 | .restart = cns3xxx_restart, | ||
397 | MACHINE_END | ||