aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2010-07-22 11:00:55 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2010-07-22 11:00:55 -0400
commitcb86ae95a0168be2acc6c48b1671ffaba1e5e39e (patch)
tree4eb05040fcb450d24817294050536d328588c7d9
parent14764b01a5576ce23a9d0c95a027049206a19cef (diff)
parent23f5cace4f858ddf40eb0ee77b984d329fd23518 (diff)
Merge branch 'master' of git://git.infradead.org/users/cbou/linux-cns3xxx into devel-stable
-rw-r--r--arch/arm/Kconfig3
-rw-r--r--arch/arm/mach-cns3xxx/Makefile3
-rw-r--r--arch/arm/mach-cns3xxx/cns3420vb.c4
-rw-r--r--arch/arm/mach-cns3xxx/devices.c111
-rw-r--r--arch/arm/mach-cns3xxx/devices.h20
-rw-r--r--arch/arm/mach-cns3xxx/include/mach/cns3xxx.h91
-rw-r--r--arch/arm/mach-cns3xxx/pcie.c389
-rw-r--r--arch/arm/mach-cns3xxx/pm.c31
8 files changed, 596 insertions, 56 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 44b6d9b42483..c1e0cdfd1147 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -301,6 +301,7 @@ config ARCH_CNS3XXX
301 select CPU_V6 301 select CPU_V6
302 select GENERIC_CLOCKEVENTS 302 select GENERIC_CLOCKEVENTS
303 select ARM_GIC 303 select ARM_GIC
304 select PCI_DOMAINS if PCI
304 help 305 help
305 Support for Cavium Networks CNS3XXX platform. 306 Support for Cavium Networks CNS3XXX platform.
306 307
@@ -1061,7 +1062,7 @@ config ISA_DMA_API
1061 bool 1062 bool
1062 1063
1063config PCI 1064config PCI
1064 bool "PCI support" if ARCH_INTEGRATOR_AP || ARCH_VERSATILE_PB || ARCH_IXP4XX || ARCH_KS8695 || MACH_ARMCORE 1065 bool "PCI support" if ARCH_INTEGRATOR_AP || ARCH_VERSATILE_PB || ARCH_IXP4XX || ARCH_KS8695 || MACH_ARMCORE || ARCH_CNS3XXX
1065 help 1066 help
1066 Find out whether you have a PCI motherboard. PCI is the name of a 1067 Find out whether you have a PCI motherboard. PCI is the name of a
1067 bus system, i.e. the way the CPU talks to the other stuff inside 1068 bus system, i.e. the way the CPU talks to the other stuff inside
diff --git a/arch/arm/mach-cns3xxx/Makefile b/arch/arm/mach-cns3xxx/Makefile
index 427507a2d696..11033f1c2e23 100644
--- a/arch/arm/mach-cns3xxx/Makefile
+++ b/arch/arm/mach-cns3xxx/Makefile
@@ -1,2 +1,3 @@
1obj-$(CONFIG_ARCH_CNS3XXX) += core.o pm.o 1obj-$(CONFIG_ARCH_CNS3XXX) += core.o pm.o devices.o
2obj-$(CONFIG_PCI) += pcie.o
2obj-$(CONFIG_MACH_CNS3420VB) += cns3420vb.o 3obj-$(CONFIG_MACH_CNS3420VB) += cns3420vb.o
diff --git a/arch/arm/mach-cns3xxx/cns3420vb.c b/arch/arm/mach-cns3xxx/cns3420vb.c
index 2e30c8288740..9df8391fd78a 100644
--- a/arch/arm/mach-cns3xxx/cns3420vb.c
+++ b/arch/arm/mach-cns3xxx/cns3420vb.c
@@ -32,6 +32,7 @@
32#include <mach/cns3xxx.h> 32#include <mach/cns3xxx.h>
33#include <mach/irqs.h> 33#include <mach/irqs.h>
34#include "core.h" 34#include "core.h"
35#include "devices.h"
35 36
36/* 37/*
37 * NOR Flash 38 * NOR Flash
@@ -117,6 +118,9 @@ static void __init cns3420_init(void)
117{ 118{
118 platform_add_devices(cns3420_pdevs, ARRAY_SIZE(cns3420_pdevs)); 119 platform_add_devices(cns3420_pdevs, ARRAY_SIZE(cns3420_pdevs));
119 120
121 cns3xxx_ahci_init();
122 cns3xxx_sdhci_init();
123
120 pm_power_off = cns3xxx_power_off; 124 pm_power_off = cns3xxx_power_off;
121} 125}
122 126
diff --git a/arch/arm/mach-cns3xxx/devices.c b/arch/arm/mach-cns3xxx/devices.c
new file mode 100644
index 000000000000..50b4d31c27c0
--- /dev/null
+++ b/arch/arm/mach-cns3xxx/devices.c
@@ -0,0 +1,111 @@
1/*
2 * CNS3xxx common devices
3 *
4 * Copyright 2008 Cavium Networks
5 * Scott Shu
6 * Copyright 2010 MontaVista Software, LLC.
7 * Anton Vorontsov <avorontsov@mvista.com>
8 *
9 * This file is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License, Version 2, as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/io.h>
15#include <linux/init.h>
16#include <linux/compiler.h>
17#include <linux/dma-mapping.h>
18#include <linux/platform_device.h>
19#include <mach/cns3xxx.h>
20#include <mach/irqs.h>
21#include "core.h"
22#include "devices.h"
23
24/*
25 * AHCI
26 */
27static struct resource cns3xxx_ahci_resource[] = {
28 [0] = {
29 .start = CNS3XXX_SATA2_BASE,
30 .end = CNS3XXX_SATA2_BASE + CNS3XXX_SATA2_SIZE - 1,
31 .flags = IORESOURCE_MEM,
32 },
33 [1] = {
34 .start = IRQ_CNS3XXX_SATA,
35 .end = IRQ_CNS3XXX_SATA,
36 .flags = IORESOURCE_IRQ,
37 },
38};
39
40static u64 cns3xxx_ahci_dmamask = DMA_BIT_MASK(32);
41
42static struct platform_device cns3xxx_ahci_pdev = {
43 .name = "ahci",
44 .id = 0,
45 .resource = cns3xxx_ahci_resource,
46 .num_resources = ARRAY_SIZE(cns3xxx_ahci_resource),
47 .dev = {
48 .dma_mask = &cns3xxx_ahci_dmamask,
49 .coherent_dma_mask = DMA_BIT_MASK(32),
50 },
51};
52
53void __init cns3xxx_ahci_init(void)
54{
55 u32 tmp;
56
57 tmp = __raw_readl(MISC_SATA_POWER_MODE);
58 tmp |= 0x1 << 16; /* Disable SATA PHY 0 from SLUMBER Mode */
59 tmp |= 0x1 << 17; /* Disable SATA PHY 1 from SLUMBER Mode */
60 __raw_writel(tmp, MISC_SATA_POWER_MODE);
61
62 /* Enable SATA PHY */
63 cns3xxx_pwr_power_up(0x1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_SATA_PHY0);
64 cns3xxx_pwr_power_up(0x1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_SATA_PHY1);
65
66 /* Enable SATA Clock */
67 cns3xxx_pwr_clk_en(0x1 << PM_CLK_GATE_REG_OFFSET_SATA);
68
69 /* De-Asscer SATA Reset */
70 cns3xxx_pwr_soft_rst(CNS3XXX_PWR_SOFTWARE_RST(SATA));
71
72 platform_device_register(&cns3xxx_ahci_pdev);
73}
74
75/*
76 * SDHCI
77 */
78static struct resource cns3xxx_sdhci_resources[] = {
79 [0] = {
80 .start = CNS3XXX_SDIO_BASE,
81 .end = CNS3XXX_SDIO_BASE + SZ_4K - 1,
82 .flags = IORESOURCE_MEM,
83 },
84 [1] = {
85 .start = IRQ_CNS3XXX_SDIO,
86 .end = IRQ_CNS3XXX_SDIO,
87 .flags = IORESOURCE_IRQ,
88 },
89};
90
91static struct platform_device cns3xxx_sdhci_pdev = {
92 .name = "sdhci-cns3xxx",
93 .id = 0,
94 .num_resources = ARRAY_SIZE(cns3xxx_sdhci_resources),
95 .resource = cns3xxx_sdhci_resources,
96};
97
98void __init cns3xxx_sdhci_init(void)
99{
100 u32 __iomem *gpioa = __io(CNS3XXX_MISC_BASE_VIRT + 0x0014);
101 u32 gpioa_pins = __raw_readl(gpioa);
102
103 /* MMC/SD pins share with GPIOA */
104 gpioa_pins |= 0x1fff0004;
105 __raw_writel(gpioa_pins, gpioa);
106
107 cns3xxx_pwr_clk_en(CNS3XXX_PWR_CLK_EN(SDIO));
108 cns3xxx_pwr_soft_rst(CNS3XXX_PWR_SOFTWARE_RST(SDIO));
109
110 platform_device_register(&cns3xxx_sdhci_pdev);
111}
diff --git a/arch/arm/mach-cns3xxx/devices.h b/arch/arm/mach-cns3xxx/devices.h
new file mode 100644
index 000000000000..27e15a10aa85
--- /dev/null
+++ b/arch/arm/mach-cns3xxx/devices.h
@@ -0,0 +1,20 @@
1/*
2 * CNS3xxx common devices
3 *
4 * Copyright 2008 Cavium Networks
5 * Scott Shu
6 * Copyright 2010 MontaVista Software, LLC.
7 * Anton Vorontsov <avorontsov@mvista.com>
8 *
9 * This file is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License, Version 2, as
11 * published by the Free Software Foundation.
12 */
13
14#ifndef __CNS3XXX_DEVICES_H_
15#define __CNS3XXX_DEVICES_H_
16
17void __init cns3xxx_ahci_init(void);
18void __init cns3xxx_sdhci_init(void);
19
20#endif /* __CNS3XXX_DEVICES_H_ */
diff --git a/arch/arm/mach-cns3xxx/include/mach/cns3xxx.h b/arch/arm/mach-cns3xxx/include/mach/cns3xxx.h
index 8a2f5a21d4ee..6dbce13771ca 100644
--- a/arch/arm/mach-cns3xxx/include/mach/cns3xxx.h
+++ b/arch/arm/mach-cns3xxx/include/mach/cns3xxx.h
@@ -247,37 +247,36 @@
247 * Misc block 247 * Misc block
248 */ 248 */
249#define MISC_MEM_MAP(offs) (void __iomem *)(CNS3XXX_MISC_BASE_VIRT + (offs)) 249#define MISC_MEM_MAP(offs) (void __iomem *)(CNS3XXX_MISC_BASE_VIRT + (offs))
250#define MISC_MEM_MAP_VALUE(offset) (*((volatile unsigned int *)(CNS3XXX_MISC_BASE_VIRT + (offset)))) 250
251 251#define MISC_MEMORY_REMAP_REG MISC_MEM_MAP(0x00)
252#define MISC_MEMORY_REMAP_REG MISC_MEM_MAP_VALUE(0x00) 252#define MISC_CHIP_CONFIG_REG MISC_MEM_MAP(0x04)
253#define MISC_CHIP_CONFIG_REG MISC_MEM_MAP_VALUE(0x04) 253#define MISC_DEBUG_PROBE_DATA_REG MISC_MEM_MAP(0x08)
254#define MISC_DEBUG_PROBE_DATA_REG MISC_MEM_MAP_VALUE(0x08) 254#define MISC_DEBUG_PROBE_SELECTION_REG MISC_MEM_MAP(0x0C)
255#define MISC_DEBUG_PROBE_SELECTION_REG MISC_MEM_MAP_VALUE(0x0C) 255#define MISC_IO_PIN_FUNC_SELECTION_REG MISC_MEM_MAP(0x10)
256#define MISC_IO_PIN_FUNC_SELECTION_REG MISC_MEM_MAP_VALUE(0x10) 256#define MISC_GPIOA_PIN_ENABLE_REG MISC_MEM_MAP(0x14)
257#define MISC_GPIOA_PIN_ENABLE_REG MISC_MEM_MAP_VALUE(0x14) 257#define MISC_GPIOB_PIN_ENABLE_REG MISC_MEM_MAP(0x18)
258#define MISC_GPIOB_PIN_ENABLE_REG MISC_MEM_MAP_VALUE(0x18) 258#define MISC_IO_PAD_DRIVE_STRENGTH_CTRL_A MISC_MEM_MAP(0x1C)
259#define MISC_IO_PAD_DRIVE_STRENGTH_CTRL_A MISC_MEM_MAP_VALUE(0x1C) 259#define MISC_IO_PAD_DRIVE_STRENGTH_CTRL_B MISC_MEM_MAP(0x20)
260#define MISC_IO_PAD_DRIVE_STRENGTH_CTRL_B MISC_MEM_MAP_VALUE(0x20) 260#define MISC_GPIOA_15_0_PULL_CTRL_REG MISC_MEM_MAP(0x24)
261#define MISC_GPIOA_15_0_PULL_CTRL_REG MISC_MEM_MAP_VALUE(0x24) 261#define MISC_GPIOA_16_31_PULL_CTRL_REG MISC_MEM_MAP(0x28)
262#define MISC_GPIOA_16_31_PULL_CTRL_REG MISC_MEM_MAP_VALUE(0x28) 262#define MISC_GPIOB_15_0_PULL_CTRL_REG MISC_MEM_MAP(0x2C)
263#define MISC_GPIOB_15_0_PULL_CTRL_REG MISC_MEM_MAP_VALUE(0x2C) 263#define MISC_GPIOB_16_31_PULL_CTRL_REG MISC_MEM_MAP(0x30)
264#define MISC_GPIOB_16_31_PULL_CTRL_REG MISC_MEM_MAP_VALUE(0x30) 264#define MISC_IO_PULL_CTRL_REG MISC_MEM_MAP(0x34)
265#define MISC_IO_PULL_CTRL_REG MISC_MEM_MAP_VALUE(0x34) 265#define MISC_E_FUSE_31_0_REG MISC_MEM_MAP(0x40)
266#define MISC_E_FUSE_31_0_REG MISC_MEM_MAP_VALUE(0x40) 266#define MISC_E_FUSE_63_32_REG MISC_MEM_MAP(0x44)
267#define MISC_E_FUSE_63_32_REG MISC_MEM_MAP_VALUE(0x44) 267#define MISC_E_FUSE_95_64_REG MISC_MEM_MAP(0x48)
268#define MISC_E_FUSE_95_64_REG MISC_MEM_MAP_VALUE(0x48) 268#define MISC_E_FUSE_127_96_REG MISC_MEM_MAP(0x4C)
269#define MISC_E_FUSE_127_96_REG MISC_MEM_MAP_VALUE(0x4C) 269#define MISC_SOFTWARE_TEST_1_REG MISC_MEM_MAP(0x50)
270#define MISC_SOFTWARE_TEST_1_REG MISC_MEM_MAP_VALUE(0x50) 270#define MISC_SOFTWARE_TEST_2_REG MISC_MEM_MAP(0x54)
271#define MISC_SOFTWARE_TEST_2_REG MISC_MEM_MAP_VALUE(0x54) 271
272 272#define MISC_SATA_POWER_MODE MISC_MEM_MAP(0x310)
273#define MISC_SATA_POWER_MODE MISC_MEM_MAP_VALUE(0x310) 273
274 274#define MISC_USB_CFG_REG MISC_MEM_MAP(0x800)
275#define MISC_USB_CFG_REG MISC_MEM_MAP_VALUE(0x800) 275#define MISC_USB_STS_REG MISC_MEM_MAP(0x804)
276#define MISC_USB_STS_REG MISC_MEM_MAP_VALUE(0x804) 276#define MISC_USBPHY00_CFG_REG MISC_MEM_MAP(0x808)
277#define MISC_USBPHY00_CFG_REG MISC_MEM_MAP_VALUE(0x808) 277#define MISC_USBPHY01_CFG_REG MISC_MEM_MAP(0x80c)
278#define MISC_USBPHY01_CFG_REG MISC_MEM_MAP_VALUE(0x80c) 278#define MISC_USBPHY10_CFG_REG MISC_MEM_MAP(0x810)
279#define MISC_USBPHY10_CFG_REG MISC_MEM_MAP_VALUE(0x810) 279#define MISC_USBPHY11_CFG_REG MISC_MEM_MAP(0x814)
280#define MISC_USBPHY11_CFG_REG MISC_MEM_MAP_VALUE(0x814)
281 280
282#define MISC_PCIEPHY_CMCTL(x) MISC_MEM_MAP(0x900 + (x) * 0x004) 281#define MISC_PCIEPHY_CMCTL(x) MISC_MEM_MAP(0x900 + (x) * 0x004)
283#define MISC_PCIEPHY_CTL(x) MISC_MEM_MAP(0x940 + (x) * 0x100) 282#define MISC_PCIEPHY_CTL(x) MISC_MEM_MAP(0x940 + (x) * 0x100)
@@ -300,21 +299,21 @@
300/* 299/*
301 * Power management and clock control 300 * Power management and clock control
302 */ 301 */
303#define PMU_REG_VALUE(offset) (*((volatile unsigned int *)(CNS3XXX_PM_BASE_VIRT + (offset)))) 302#define PMU_MEM_MAP(offs) (void __iomem *)(CNS3XXX_PM_BASE_VIRT + (offs))
304 303
305#define PM_CLK_GATE_REG PMU_REG_VALUE(0x000) 304#define PM_CLK_GATE_REG PMU_MEM_MAP(0x000)
306#define PM_SOFT_RST_REG PMU_REG_VALUE(0x004) 305#define PM_SOFT_RST_REG PMU_MEM_MAP(0x004)
307#define PM_HS_CFG_REG PMU_REG_VALUE(0x008) 306#define PM_HS_CFG_REG PMU_MEM_MAP(0x008)
308#define PM_CACTIVE_STA_REG PMU_REG_VALUE(0x00C) 307#define PM_CACTIVE_STA_REG PMU_MEM_MAP(0x00C)
309#define PM_PWR_STA_REG PMU_REG_VALUE(0x010) 308#define PM_PWR_STA_REG PMU_MEM_MAP(0x010)
310#define PM_CLK_CTRL_REG PMU_REG_VALUE(0x014) 309#define PM_CLK_CTRL_REG PMU_MEM_MAP(0x014)
311#define PM_PLL_LCD_I2S_CTRL_REG PMU_REG_VALUE(0x018) 310#define PM_PLL_LCD_I2S_CTRL_REG PMU_MEM_MAP(0x018)
312#define PM_PLL_HM_PD_CTRL_REG PMU_REG_VALUE(0x01C) 311#define PM_PLL_HM_PD_CTRL_REG PMU_MEM_MAP(0x01C)
313#define PM_REGULAT_CTRL_REG PMU_REG_VALUE(0x020) 312#define PM_REGULAT_CTRL_REG PMU_MEM_MAP(0x020)
314#define PM_WDT_CTRL_REG PMU_REG_VALUE(0x024) 313#define PM_WDT_CTRL_REG PMU_MEM_MAP(0x024)
315#define PM_WU_CTRL0_REG PMU_REG_VALUE(0x028) 314#define PM_WU_CTRL0_REG PMU_MEM_MAP(0x028)
316#define PM_WU_CTRL1_REG PMU_REG_VALUE(0x02C) 315#define PM_WU_CTRL1_REG PMU_MEM_MAP(0x02C)
317#define PM_CSR_REG PMU_REG_VALUE(0x030) 316#define PM_CSR_REG PMU_MEM_MAP(0x030)
318 317
319/* PM_CLK_GATE_REG */ 318/* PM_CLK_GATE_REG */
320#define PM_CLK_GATE_REG_OFFSET_SDIO (25) 319#define PM_CLK_GATE_REG_OFFSET_SDIO (25)
diff --git a/arch/arm/mach-cns3xxx/pcie.c b/arch/arm/mach-cns3xxx/pcie.c
new file mode 100644
index 000000000000..38088c36936c
--- /dev/null
+++ b/arch/arm/mach-cns3xxx/pcie.c
@@ -0,0 +1,389 @@
1/*
2 * PCI-E support for CNS3xxx
3 *
4 * Copyright 2008 Cavium Networks
5 * Richard Liu <richard.liu@caviumnetworks.com>
6 * Copyright 2010 MontaVista Software, LLC.
7 * Anton Vorontsov <avorontsov@mvista.com>
8 *
9 * This file is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License, Version 2, as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/init.h>
15#include <linux/kernel.h>
16#include <linux/bug.h>
17#include <linux/pci.h>
18#include <linux/io.h>
19#include <linux/ioport.h>
20#include <linux/interrupt.h>
21#include <linux/ptrace.h>
22#include <asm/mach/map.h>
23#include <mach/cns3xxx.h>
24#include "core.h"
25
26enum cns3xxx_access_type {
27 CNS3XXX_HOST_TYPE = 0,
28 CNS3XXX_CFG0_TYPE,
29 CNS3XXX_CFG1_TYPE,
30 CNS3XXX_NUM_ACCESS_TYPES,
31};
32
33struct cns3xxx_pcie {
34 struct map_desc cfg_bases[CNS3XXX_NUM_ACCESS_TYPES];
35 unsigned int irqs[2];
36 struct resource res_io;
37 struct resource res_mem;
38 struct hw_pci hw_pci;
39
40 bool linked;
41};
42
43static struct cns3xxx_pcie cns3xxx_pcie[]; /* forward decl. */
44
45static struct cns3xxx_pcie *sysdata_to_cnspci(void *sysdata)
46{
47 struct pci_sys_data *root = sysdata;
48
49 return &cns3xxx_pcie[root->domain];
50}
51
52static struct cns3xxx_pcie *pdev_to_cnspci(struct pci_dev *dev)
53{
54 return sysdata_to_cnspci(dev->sysdata);
55}
56
57static struct cns3xxx_pcie *pbus_to_cnspci(struct pci_bus *bus)
58{
59 return sysdata_to_cnspci(bus->sysdata);
60}
61
62static void __iomem *cns3xxx_pci_cfg_base(struct pci_bus *bus,
63 unsigned int devfn, int where)
64{
65 struct cns3xxx_pcie *cnspci = pbus_to_cnspci(bus);
66 int busno = bus->number;
67 int slot = PCI_SLOT(devfn);
68 int offset;
69 enum cns3xxx_access_type type;
70 void __iomem *base;
71
72 /* If there is no link, just show the CNS PCI bridge. */
73 if (!cnspci->linked && (busno > 0 || slot > 0))
74 return NULL;
75
76 /*
77 * The CNS PCI bridge doesn't fit into the PCI hierarchy, though
78 * we still want to access it. For this to work, we must place
79 * the first device on the same bus as the CNS PCI bridge.
80 */
81 if (busno == 0) {
82 if (slot > 1)
83 return NULL;
84 type = slot;
85 } else {
86 type = CNS3XXX_CFG1_TYPE;
87 }
88
89 base = (void __iomem *)cnspci->cfg_bases[type].virtual;
90 offset = ((busno & 0xf) << 20) | (devfn << 12) | (where & 0xffc);
91
92 return base + offset;
93}
94
95static int cns3xxx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
96 int where, int size, u32 *val)
97{
98 u32 v;
99 void __iomem *base;
100 u32 mask = (0x1ull << (size * 8)) - 1;
101 int shift = (where % 4) * 8;
102
103 base = cns3xxx_pci_cfg_base(bus, devfn, where);
104 if (!base) {
105 *val = 0xffffffff;
106 return PCIBIOS_SUCCESSFUL;
107 }
108
109 v = __raw_readl(base);
110
111 if (bus->number == 0 && devfn == 0 &&
112 (where & 0xffc) == PCI_CLASS_REVISION) {
113 /*
114 * RC's class is 0xb, but Linux PCI driver needs 0x604
115 * for a PCIe bridge. So we must fixup the class code
116 * to 0x604 here.
117 */
118 v &= 0xff;
119 v |= 0x604 << 16;
120 }
121
122 *val = (v >> shift) & mask;
123
124 return PCIBIOS_SUCCESSFUL;
125}
126
127static int cns3xxx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
128 int where, int size, u32 val)
129{
130 u32 v;
131 void __iomem *base;
132 u32 mask = (0x1ull << (size * 8)) - 1;
133 int shift = (where % 4) * 8;
134
135 base = cns3xxx_pci_cfg_base(bus, devfn, where);
136 if (!base)
137 return PCIBIOS_SUCCESSFUL;
138
139 v = __raw_readl(base);
140
141 v &= ~(mask << shift);
142 v |= (val & mask) << shift;
143
144 __raw_writel(v, base);
145
146 return PCIBIOS_SUCCESSFUL;
147}
148
149static int cns3xxx_pci_setup(int nr, struct pci_sys_data *sys)
150{
151 struct cns3xxx_pcie *cnspci = sysdata_to_cnspci(sys);
152 struct resource *res_io = &cnspci->res_io;
153 struct resource *res_mem = &cnspci->res_mem;
154 struct resource **sysres = sys->resource;
155
156 BUG_ON(request_resource(&iomem_resource, res_io) ||
157 request_resource(&iomem_resource, res_mem));
158
159 sysres[0] = res_io;
160 sysres[1] = res_mem;
161
162 return 1;
163}
164
165static struct pci_ops cns3xxx_pcie_ops = {
166 .read = cns3xxx_pci_read_config,
167 .write = cns3xxx_pci_write_config,
168};
169
170static struct pci_bus *cns3xxx_pci_scan_bus(int nr, struct pci_sys_data *sys)
171{
172 return pci_scan_bus(sys->busnr, &cns3xxx_pcie_ops, sys);
173}
174
175static int cns3xxx_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
176{
177 struct cns3xxx_pcie *cnspci = pdev_to_cnspci(dev);
178 int irq = cnspci->irqs[slot];
179
180 pr_info("PCIe map irq: %04d:%02x:%02x.%02x slot %d, pin %d, irq: %d\n",
181 pci_domain_nr(dev->bus), dev->bus->number, PCI_SLOT(dev->devfn),
182 PCI_FUNC(dev->devfn), slot, pin, irq);
183
184 return irq;
185}
186
187static struct cns3xxx_pcie cns3xxx_pcie[] = {
188 [0] = {
189 .cfg_bases = {
190 [CNS3XXX_HOST_TYPE] = {
191 .virtual = CNS3XXX_PCIE0_HOST_BASE_VIRT,
192 .pfn = __phys_to_pfn(CNS3XXX_PCIE0_HOST_BASE),
193 .length = SZ_16M,
194 .type = MT_DEVICE,
195 },
196 [CNS3XXX_CFG0_TYPE] = {
197 .virtual = CNS3XXX_PCIE0_CFG0_BASE_VIRT,
198 .pfn = __phys_to_pfn(CNS3XXX_PCIE0_CFG0_BASE),
199 .length = SZ_16M,
200 .type = MT_DEVICE,
201 },
202 [CNS3XXX_CFG1_TYPE] = {
203 .virtual = CNS3XXX_PCIE0_CFG1_BASE_VIRT,
204 .pfn = __phys_to_pfn(CNS3XXX_PCIE0_CFG1_BASE),
205 .length = SZ_16M,
206 .type = MT_DEVICE,
207 },
208 },
209 .res_io = {
210 .name = "PCIe0 I/O space",
211 .start = CNS3XXX_PCIE0_IO_BASE,
212 .end = CNS3XXX_PCIE0_IO_BASE + SZ_16M - 1,
213 .flags = IORESOURCE_IO,
214 },
215 .res_mem = {
216 .name = "PCIe0 non-prefetchable",
217 .start = CNS3XXX_PCIE0_MEM_BASE,
218 .end = CNS3XXX_PCIE0_MEM_BASE + SZ_16M - 1,
219 .flags = IORESOURCE_MEM,
220 },
221 .irqs = { IRQ_CNS3XXX_PCIE0_RC, IRQ_CNS3XXX_PCIE0_DEVICE, },
222 .hw_pci = {
223 .domain = 0,
224 .swizzle = pci_std_swizzle,
225 .nr_controllers = 1,
226 .setup = cns3xxx_pci_setup,
227 .scan = cns3xxx_pci_scan_bus,
228 .map_irq = cns3xxx_pcie_map_irq,
229 },
230 },
231 [1] = {
232 .cfg_bases = {
233 [CNS3XXX_HOST_TYPE] = {
234 .virtual = CNS3XXX_PCIE1_HOST_BASE_VIRT,
235 .pfn = __phys_to_pfn(CNS3XXX_PCIE1_HOST_BASE),
236 .length = SZ_16M,
237 .type = MT_DEVICE,
238 },
239 [CNS3XXX_CFG0_TYPE] = {
240 .virtual = CNS3XXX_PCIE1_CFG0_BASE_VIRT,
241 .pfn = __phys_to_pfn(CNS3XXX_PCIE1_CFG0_BASE),
242 .length = SZ_16M,
243 .type = MT_DEVICE,
244 },
245 [CNS3XXX_CFG1_TYPE] = {
246 .virtual = CNS3XXX_PCIE1_CFG1_BASE_VIRT,
247 .pfn = __phys_to_pfn(CNS3XXX_PCIE1_CFG1_BASE),
248 .length = SZ_16M,
249 .type = MT_DEVICE,
250 },
251 },
252 .res_io = {
253 .name = "PCIe1 I/O space",
254 .start = CNS3XXX_PCIE1_IO_BASE,
255 .end = CNS3XXX_PCIE1_IO_BASE + SZ_16M - 1,
256 .flags = IORESOURCE_IO,
257 },
258 .res_mem = {
259 .name = "PCIe1 non-prefetchable",
260 .start = CNS3XXX_PCIE1_MEM_BASE,
261 .end = CNS3XXX_PCIE1_MEM_BASE + SZ_16M - 1,
262 .flags = IORESOURCE_MEM,
263 },
264 .irqs = { IRQ_CNS3XXX_PCIE1_RC, IRQ_CNS3XXX_PCIE1_DEVICE, },
265 .hw_pci = {
266 .domain = 1,
267 .swizzle = pci_std_swizzle,
268 .nr_controllers = 1,
269 .setup = cns3xxx_pci_setup,
270 .scan = cns3xxx_pci_scan_bus,
271 .map_irq = cns3xxx_pcie_map_irq,
272 },
273 },
274};
275
276static void __init cns3xxx_pcie_check_link(struct cns3xxx_pcie *cnspci)
277{
278 int port = cnspci->hw_pci.domain;
279 u32 reg;
280 unsigned long time;
281
282 reg = __raw_readl(MISC_PCIE_CTRL(port));
283 /*
284 * Enable Application Request to 1, it will exit L1 automatically,
285 * but when chip back, it will use another clock, still can use 0x1.
286 */
287 reg |= 0x3;
288 __raw_writel(reg, MISC_PCIE_CTRL(port));
289
290 pr_info("PCIe: Port[%d] Enable PCIe LTSSM\n", port);
291 pr_info("PCIe: Port[%d] Check data link layer...", port);
292
293 time = jiffies;
294 while (1) {
295 reg = __raw_readl(MISC_PCIE_PM_DEBUG(port));
296 if (reg & 0x1) {
297 pr_info("Link up.\n");
298 cnspci->linked = 1;
299 break;
300 } else if (time_after(jiffies, time + 50)) {
301 pr_info("Device not found.\n");
302 break;
303 }
304 }
305}
306
307static void __init cns3xxx_pcie_hw_init(struct cns3xxx_pcie *cnspci)
308{
309 int port = cnspci->hw_pci.domain;
310 struct pci_sys_data sd = {
311 .domain = port,
312 };
313 struct pci_bus bus = {
314 .number = 0,
315 .ops = &cns3xxx_pcie_ops,
316 .sysdata = &sd,
317 };
318 u32 io_base = cnspci->res_io.start >> 16;
319 u32 mem_base = cnspci->res_mem.start >> 16;
320 u32 host_base = cnspci->cfg_bases[CNS3XXX_HOST_TYPE].pfn;
321 u32 cfg0_base = cnspci->cfg_bases[CNS3XXX_CFG0_TYPE].pfn;
322 u32 devfn = 0;
323 u8 tmp8;
324 u16 pos;
325 u16 dc;
326
327 host_base = (__pfn_to_phys(host_base) - 1) >> 16;
328 cfg0_base = (__pfn_to_phys(cfg0_base) - 1) >> 16;
329
330 pci_bus_write_config_byte(&bus, devfn, PCI_PRIMARY_BUS, 0);
331 pci_bus_write_config_byte(&bus, devfn, PCI_SECONDARY_BUS, 1);
332 pci_bus_write_config_byte(&bus, devfn, PCI_SUBORDINATE_BUS, 1);
333
334 pci_bus_read_config_byte(&bus, devfn, PCI_PRIMARY_BUS, &tmp8);
335 pci_bus_read_config_byte(&bus, devfn, PCI_SECONDARY_BUS, &tmp8);
336 pci_bus_read_config_byte(&bus, devfn, PCI_SUBORDINATE_BUS, &tmp8);
337
338 pci_bus_write_config_word(&bus, devfn, PCI_MEMORY_BASE, mem_base);
339 pci_bus_write_config_word(&bus, devfn, PCI_MEMORY_LIMIT, host_base);
340 pci_bus_write_config_word(&bus, devfn, PCI_IO_BASE_UPPER16, io_base);
341 pci_bus_write_config_word(&bus, devfn, PCI_IO_LIMIT_UPPER16, cfg0_base);
342
343 if (!cnspci->linked)
344 return;
345
346 /* Set Device Max_Read_Request_Size to 128 byte */
347 devfn = PCI_DEVFN(1, 0);
348 pos = pci_bus_find_capability(&bus, devfn, PCI_CAP_ID_EXP);
349 pci_bus_read_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, &dc);
350 dc &= ~(0x3 << 12); /* Clear Device Control Register [14:12] */
351 pci_bus_write_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, dc);
352 pci_bus_read_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, &dc);
353 if (!(dc & (0x3 << 12)))
354 pr_info("PCIe: Set Device Max_Read_Request_Size to 128 byte\n");
355
356 /* Disable PCIe0 Interrupt Mask INTA to INTD */
357 __raw_writel(~0x3FFF, MISC_PCIE_INT_MASK(port));
358}
359
360static int cns3xxx_pcie_abort_handler(unsigned long addr, unsigned int fsr,
361 struct pt_regs *regs)
362{
363 if (fsr & (1 << 10))
364 regs->ARM_pc += 4;
365 return 0;
366}
367
368static int __init cns3xxx_pcie_init(void)
369{
370 int i;
371
372 hook_fault_code(16 + 6, cns3xxx_pcie_abort_handler, SIGBUS,
373 "imprecise external abort");
374
375 for (i = 0; i < ARRAY_SIZE(cns3xxx_pcie); i++) {
376 iotable_init(cns3xxx_pcie[i].cfg_bases,
377 ARRAY_SIZE(cns3xxx_pcie[i].cfg_bases));
378 cns3xxx_pwr_clk_en(0x1 << PM_CLK_GATE_REG_OFFSET_PCIE(i));
379 cns3xxx_pwr_soft_rst(0x1 << PM_SOFT_RST_REG_OFFST_PCIE(i));
380 cns3xxx_pcie_check_link(&cns3xxx_pcie[i]);
381 cns3xxx_pcie_hw_init(&cns3xxx_pcie[i]);
382 pci_common_init(&cns3xxx_pcie[i].hw_pci);
383 }
384
385 pci_assign_unassigned_resources();
386
387 return 0;
388}
389device_initcall(cns3xxx_pcie_init);
diff --git a/arch/arm/mach-cns3xxx/pm.c b/arch/arm/mach-cns3xxx/pm.c
index 725e1a4fc231..38e44706feab 100644
--- a/arch/arm/mach-cns3xxx/pm.c
+++ b/arch/arm/mach-cns3xxx/pm.c
@@ -6,18 +6,25 @@
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include <linux/io.h>
9#include <linux/delay.h> 10#include <linux/delay.h>
10#include <mach/system.h> 11#include <mach/system.h>
11#include <mach/cns3xxx.h> 12#include <mach/cns3xxx.h>
12 13
13void cns3xxx_pwr_clk_en(unsigned int block) 14void cns3xxx_pwr_clk_en(unsigned int block)
14{ 15{
15 PM_CLK_GATE_REG |= (block & PM_CLK_GATE_REG_MASK); 16 u32 reg = __raw_readl(PM_CLK_GATE_REG);
17
18 reg |= (block & PM_CLK_GATE_REG_MASK);
19 __raw_writel(reg, PM_CLK_GATE_REG);
16} 20}
17 21
18void cns3xxx_pwr_power_up(unsigned int block) 22void cns3xxx_pwr_power_up(unsigned int block)
19{ 23{
20 PM_PLL_HM_PD_CTRL_REG &= ~(block & CNS3XXX_PWR_PLL_ALL); 24 u32 reg = __raw_readl(PM_PLL_HM_PD_CTRL_REG);
25
26 reg &= ~(block & CNS3XXX_PWR_PLL_ALL);
27 __raw_writel(reg, PM_PLL_HM_PD_CTRL_REG);
21 28
22 /* Wait for 300us for the PLL output clock locked. */ 29 /* Wait for 300us for the PLL output clock locked. */
23 udelay(300); 30 udelay(300);
@@ -25,22 +32,29 @@ void cns3xxx_pwr_power_up(unsigned int block)
25 32
26void cns3xxx_pwr_power_down(unsigned int block) 33void cns3xxx_pwr_power_down(unsigned int block)
27{ 34{
35 u32 reg = __raw_readl(PM_PLL_HM_PD_CTRL_REG);
36
28 /* write '1' to power down */ 37 /* write '1' to power down */
29 PM_PLL_HM_PD_CTRL_REG |= (block & CNS3XXX_PWR_PLL_ALL); 38 reg |= (block & CNS3XXX_PWR_PLL_ALL);
39 __raw_writel(reg, PM_PLL_HM_PD_CTRL_REG);
30}; 40};
31 41
32static void cns3xxx_pwr_soft_rst_force(unsigned int block) 42static void cns3xxx_pwr_soft_rst_force(unsigned int block)
33{ 43{
44 u32 reg = __raw_readl(PM_SOFT_RST_REG);
45
34 /* 46 /*
35 * bit 0, 28, 29 => program low to reset, 47 * bit 0, 28, 29 => program low to reset,
36 * the other else program low and then high 48 * the other else program low and then high
37 */ 49 */
38 if (block & 0x30000001) { 50 if (block & 0x30000001) {
39 PM_SOFT_RST_REG &= ~(block & PM_SOFT_RST_REG_MASK); 51 reg &= ~(block & PM_SOFT_RST_REG_MASK);
40 } else { 52 } else {
41 PM_SOFT_RST_REG &= ~(block & PM_SOFT_RST_REG_MASK); 53 reg &= ~(block & PM_SOFT_RST_REG_MASK);
42 PM_SOFT_RST_REG |= (block & PM_SOFT_RST_REG_MASK); 54 reg |= (block & PM_SOFT_RST_REG_MASK);
43 } 55 }
56
57 __raw_writel(reg, PM_SOFT_RST_REG);
44} 58}
45 59
46void cns3xxx_pwr_soft_rst(unsigned int block) 60void cns3xxx_pwr_soft_rst(unsigned int block)
@@ -73,12 +87,13 @@ void arch_reset(char mode, const char *cmd)
73 */ 87 */
74int cns3xxx_cpu_clock(void) 88int cns3xxx_cpu_clock(void)
75{ 89{
90 u32 reg = __raw_readl(PM_CLK_CTRL_REG);
76 int cpu; 91 int cpu;
77 int cpu_sel; 92 int cpu_sel;
78 int div_sel; 93 int div_sel;
79 94
80 cpu_sel = (PM_CLK_CTRL_REG >> PM_CLK_CTRL_REG_OFFSET_PLL_CPU_SEL) & 0xf; 95 cpu_sel = (reg >> PM_CLK_CTRL_REG_OFFSET_PLL_CPU_SEL) & 0xf;
81 div_sel = (PM_CLK_CTRL_REG >> PM_CLK_CTRL_REG_OFFSET_CPU_CLK_DIV) & 0x3; 96 div_sel = (reg >> PM_CLK_CTRL_REG_OFFSET_CPU_CLK_DIV) & 0x3;
82 97
83 cpu = (300 + ((cpu_sel / 3) * 100) + ((cpu_sel % 3) * 33)) >> div_sel; 98 cpu = (300 + ((cpu_sel / 3) * 100) + ((cpu_sel % 3) * 33)) >> div_sel;
84 99