diff options
Diffstat (limited to 'arch/mips/loongson')
34 files changed, 2613 insertions, 76 deletions
diff --git a/arch/mips/loongson/Kconfig b/arch/mips/loongson/Kconfig index d45092505fa1..3df1967dea08 100644 --- a/arch/mips/loongson/Kconfig +++ b/arch/mips/loongson/Kconfig | |||
@@ -1,31 +1,85 @@ | |||
1 | choice | 1 | choice |
2 | prompt "Machine Type" | 2 | prompt "Machine Type" |
3 | depends on MACH_LOONGSON | 3 | depends on MACH_LOONGSON |
4 | 4 | ||
5 | config LEMOTE_FULOONG2E | 5 | config LEMOTE_FULOONG2E |
6 | bool "Lemote Fuloong(2e) mini-PC" | 6 | bool "Lemote Fuloong(2e) mini-PC" |
7 | select ARCH_SPARSEMEM_ENABLE | 7 | select ARCH_SPARSEMEM_ENABLE |
8 | select CEVT_R4K | 8 | select CEVT_R4K |
9 | select CSRC_R4K | 9 | select CSRC_R4K |
10 | select SYS_HAS_CPU_LOONGSON2E | 10 | select SYS_HAS_CPU_LOONGSON2E |
11 | select DMA_NONCOHERENT | 11 | select DMA_NONCOHERENT |
12 | select BOOT_ELF32 | 12 | select BOOT_ELF32 |
13 | select BOARD_SCACHE | 13 | select BOARD_SCACHE |
14 | select HW_HAS_PCI | 14 | select HW_HAS_PCI |
15 | select I8259 | 15 | select I8259 |
16 | select ISA | 16 | select ISA |
17 | select IRQ_CPU | 17 | select IRQ_CPU |
18 | select SYS_SUPPORTS_32BIT_KERNEL | 18 | select SYS_SUPPORTS_32BIT_KERNEL |
19 | select SYS_SUPPORTS_64BIT_KERNEL | 19 | select SYS_SUPPORTS_64BIT_KERNEL |
20 | select SYS_SUPPORTS_LITTLE_ENDIAN | 20 | select SYS_SUPPORTS_LITTLE_ENDIAN |
21 | select SYS_SUPPORTS_HIGHMEM | 21 | select SYS_SUPPORTS_HIGHMEM |
22 | select SYS_HAS_EARLY_PRINTK | 22 | select SYS_HAS_EARLY_PRINTK |
23 | select GENERIC_HARDIRQS_NO__DO_IRQ | 23 | select GENERIC_HARDIRQS_NO__DO_IRQ |
24 | select GENERIC_ISA_DMA_SUPPORT_BROKEN | 24 | select GENERIC_ISA_DMA_SUPPORT_BROKEN |
25 | select CPU_HAS_WB | 25 | select CPU_HAS_WB |
26 | help | 26 | help |
27 | Lemote Fuloong(2e) mini-PC board based on the Chinese Loongson-2E CPU and | 27 | Lemote Fuloong(2e) mini-PC board based on the Chinese Loongson-2E CPU and |
28 | an FPGA northbridge | 28 | an FPGA northbridge |
29 | 29 | ||
30 | Lemote Fuloong(2e) mini PC have a VIA686B south bridge. | 30 | Lemote Fuloong(2e) mini PC have a VIA686B south bridge. |
31 | |||
32 | config LEMOTE_MACH2F | ||
33 | bool "Lemote Loongson 2F family machines" | ||
34 | select ARCH_SPARSEMEM_ENABLE | ||
35 | select BOARD_SCACHE | ||
36 | select BOOT_ELF32 | ||
37 | select CEVT_R4K if ! MIPS_EXTERNAL_TIMER | ||
38 | select CPU_HAS_WB | ||
39 | select CS5536 | ||
40 | select CSRC_R4K if ! MIPS_EXTERNAL_TIMER | ||
41 | select DMA_NONCOHERENT | ||
42 | select GENERIC_HARDIRQS_NO__DO_IRQ | ||
43 | select GENERIC_ISA_DMA_SUPPORT_BROKEN | ||
44 | select HW_HAS_PCI | ||
45 | select I8259 | ||
46 | select IRQ_CPU | ||
47 | select ISA | ||
48 | select SYS_HAS_CPU_LOONGSON2F | ||
49 | select SYS_HAS_EARLY_PRINTK | ||
50 | select SYS_SUPPORTS_32BIT_KERNEL | ||
51 | select SYS_SUPPORTS_64BIT_KERNEL | ||
52 | select SYS_SUPPORTS_HIGHMEM | ||
53 | select SYS_SUPPORTS_LITTLE_ENDIAN | ||
54 | help | ||
55 | Lemote Loongson 2F family machines utilize the 2F revision of | ||
56 | Loongson processor and the AMD CS5536 south bridge. | ||
57 | |||
58 | These family machines include fuloong2f mini PC, yeeloong2f notebook, | ||
59 | LingLoong allinone PC and so forth. | ||
31 | endchoice | 60 | endchoice |
61 | |||
62 | config CS5536 | ||
63 | bool | ||
64 | |||
65 | config CS5536_MFGPT | ||
66 | bool "CS5536 MFGPT Timer" | ||
67 | depends on CS5536 | ||
68 | select MIPS_EXTERNAL_TIMER | ||
69 | help | ||
70 | This option enables the mfgpt0 timer of AMD CS5536. | ||
71 | |||
72 | If you want to enable the Loongson2 CPUFreq Driver, Please enable | ||
73 | this option at first, otherwise, You will get wrong system time. | ||
74 | |||
75 | If unsure, say Yes. | ||
76 | |||
77 | config LOONGSON_SUSPEND | ||
78 | bool | ||
79 | default y | ||
80 | depends on CPU_SUPPORTS_CPUFREQ && SUSPEND | ||
81 | |||
82 | config LOONGSON_UART_BASE | ||
83 | bool | ||
84 | default y | ||
85 | depends on EARLY_PRINTK || SERIAL_8250 | ||
diff --git a/arch/mips/loongson/Makefile b/arch/mips/loongson/Makefile index 39048c455d7d..2b76cb0fb07d 100644 --- a/arch/mips/loongson/Makefile +++ b/arch/mips/loongson/Makefile | |||
@@ -9,3 +9,9 @@ obj-$(CONFIG_MACH_LOONGSON) += common/ | |||
9 | # | 9 | # |
10 | 10 | ||
11 | obj-$(CONFIG_LEMOTE_FULOONG2E) += fuloong-2e/ | 11 | obj-$(CONFIG_LEMOTE_FULOONG2E) += fuloong-2e/ |
12 | |||
13 | # | ||
14 | # Lemote loongson2f family machines | ||
15 | # | ||
16 | |||
17 | obj-$(CONFIG_LEMOTE_MACH2F) += lemote-2f/ | ||
diff --git a/arch/mips/loongson/common/Makefile b/arch/mips/loongson/common/Makefile index 656b3cc0a2a6..7668c4de1151 100644 --- a/arch/mips/loongson/common/Makefile +++ b/arch/mips/loongson/common/Makefile | |||
@@ -3,9 +3,23 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y += setup.o init.o cmdline.o env.o time.o reset.o irq.o \ | 5 | obj-y += setup.o init.o cmdline.o env.o time.o reset.o irq.o \ |
6 | pci.o bonito-irq.o mem.o machtype.o | 6 | pci.o bonito-irq.o mem.o machtype.o platform.o |
7 | 7 | ||
8 | # | 8 | # |
9 | # Early printk support | 9 | # Serial port support |
10 | # | 10 | # |
11 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | 11 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o |
12 | obj-$(CONFIG_SERIAL_8250) += serial.o | ||
13 | obj-$(CONFIG_LOONGSON_UART_BASE) += uart_base.o | ||
14 | |||
15 | # | ||
16 | # Enable CS5536 Virtual Support Module(VSM) to virtulize the PCI configure | ||
17 | # space | ||
18 | # | ||
19 | obj-$(CONFIG_CS5536) += cs5536/ | ||
20 | |||
21 | # | ||
22 | # Suspend Support | ||
23 | # | ||
24 | |||
25 | obj-$(CONFIG_LOONGSON_SUSPEND) += pm.o | ||
diff --git a/arch/mips/loongson/common/bonito-irq.c b/arch/mips/loongson/common/bonito-irq.c index 3e31e7ad713e..2dc2a4cc632a 100644 --- a/arch/mips/loongson/common/bonito-irq.c +++ b/arch/mips/loongson/common/bonito-irq.c | |||
@@ -12,18 +12,19 @@ | |||
12 | * option) any later version. | 12 | * option) any later version. |
13 | */ | 13 | */ |
14 | #include <linux/interrupt.h> | 14 | #include <linux/interrupt.h> |
15 | #include <linux/compiler.h> | ||
15 | 16 | ||
16 | #include <loongson.h> | 17 | #include <loongson.h> |
17 | 18 | ||
18 | static inline void bonito_irq_enable(unsigned int irq) | 19 | static inline void bonito_irq_enable(unsigned int irq) |
19 | { | 20 | { |
20 | BONITO_INTENSET = (1 << (irq - BONITO_IRQ_BASE)); | 21 | LOONGSON_INTENSET = (1 << (irq - LOONGSON_IRQ_BASE)); |
21 | mmiowb(); | 22 | mmiowb(); |
22 | } | 23 | } |
23 | 24 | ||
24 | static inline void bonito_irq_disable(unsigned int irq) | 25 | static inline void bonito_irq_disable(unsigned int irq) |
25 | { | 26 | { |
26 | BONITO_INTENCLR = (1 << (irq - BONITO_IRQ_BASE)); | 27 | LOONGSON_INTENCLR = (1 << (irq - LOONGSON_IRQ_BASE)); |
27 | mmiowb(); | 28 | mmiowb(); |
28 | } | 29 | } |
29 | 30 | ||
@@ -35,7 +36,7 @@ static struct irq_chip bonito_irq_type = { | |||
35 | .unmask = bonito_irq_enable, | 36 | .unmask = bonito_irq_enable, |
36 | }; | 37 | }; |
37 | 38 | ||
38 | static struct irqaction dma_timeout_irqaction = { | 39 | static struct irqaction __maybe_unused dma_timeout_irqaction = { |
39 | .handler = no_action, | 40 | .handler = no_action, |
40 | .name = "dma_timeout", | 41 | .name = "dma_timeout", |
41 | }; | 42 | }; |
@@ -44,8 +45,10 @@ void bonito_irq_init(void) | |||
44 | { | 45 | { |
45 | u32 i; | 46 | u32 i; |
46 | 47 | ||
47 | for (i = BONITO_IRQ_BASE; i < BONITO_IRQ_BASE + 32; i++) | 48 | for (i = LOONGSON_IRQ_BASE; i < LOONGSON_IRQ_BASE + 32; i++) |
48 | set_irq_chip_and_handler(i, &bonito_irq_type, handle_level_irq); | 49 | set_irq_chip_and_handler(i, &bonito_irq_type, handle_level_irq); |
49 | 50 | ||
50 | setup_irq(BONITO_IRQ_BASE + 10, &dma_timeout_irqaction); | 51 | #ifdef CONFIG_CPU_LOONGSON2E |
52 | setup_irq(LOONGSON_IRQ_BASE + 10, &dma_timeout_irqaction); | ||
53 | #endif | ||
51 | } | 54 | } |
diff --git a/arch/mips/loongson/common/cmdline.c b/arch/mips/loongson/common/cmdline.c index 75f1b243ee4e..7ad47f227477 100644 --- a/arch/mips/loongson/common/cmdline.c +++ b/arch/mips/loongson/common/cmdline.c | |||
@@ -9,7 +9,7 @@ | |||
9 | * Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology | 9 | * Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology |
10 | * Author: Fuxin Zhang, zhangfx@lemote.com | 10 | * Author: Fuxin Zhang, zhangfx@lemote.com |
11 | * | 11 | * |
12 | * Copyright (C) 2009 Lemote Inc. & Insititute of Computing Technology | 12 | * Copyright (C) 2009 Lemote Inc. |
13 | * Author: Wu Zhangjin, wuzj@lemote.com | 13 | * Author: Wu Zhangjin, wuzj@lemote.com |
14 | * | 14 | * |
15 | * This program is free software; you can redistribute it and/or modify it | 15 | * This program is free software; you can redistribute it and/or modify it |
@@ -49,4 +49,6 @@ void __init prom_init_cmdline(void) | |||
49 | strcat(arcs_cmdline, " console=ttyS0,115200"); | 49 | strcat(arcs_cmdline, " console=ttyS0,115200"); |
50 | if ((strstr(arcs_cmdline, "root=")) == NULL) | 50 | if ((strstr(arcs_cmdline, "root=")) == NULL) |
51 | strcat(arcs_cmdline, " root=/dev/hda1"); | 51 | strcat(arcs_cmdline, " root=/dev/hda1"); |
52 | |||
53 | prom_init_machtype(); | ||
52 | } | 54 | } |
diff --git a/arch/mips/loongson/common/cs5536/Makefile b/arch/mips/loongson/common/cs5536/Makefile new file mode 100644 index 000000000000..510d4cdc2378 --- /dev/null +++ b/arch/mips/loongson/common/cs5536/Makefile | |||
@@ -0,0 +1,13 @@ | |||
1 | # | ||
2 | # Makefile for CS5536 support. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_CS5536) += cs5536_pci.o cs5536_ide.o cs5536_acc.o cs5536_ohci.o \ | ||
6 | cs5536_isa.o cs5536_ehci.o | ||
7 | |||
8 | # | ||
9 | # Enable cs5536 mfgpt Timer | ||
10 | # | ||
11 | obj-$(CONFIG_CS5536_MFGPT) += cs5536_mfgpt.o | ||
12 | |||
13 | EXTRA_CFLAGS += -Werror | ||
diff --git a/arch/mips/loongson/common/cs5536/cs5536_acc.c b/arch/mips/loongson/common/cs5536/cs5536_acc.c new file mode 100644 index 000000000000..b49485f187e0 --- /dev/null +++ b/arch/mips/loongson/common/cs5536/cs5536_acc.c | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * the ACC Virtual Support Module of AMD CS5536 | ||
3 | * | ||
4 | * Copyright (C) 2007 Lemote, Inc. | ||
5 | * Author : jlliu, liujl@lemote.com | ||
6 | * | ||
7 | * Copyright (C) 2009 Lemote, Inc. | ||
8 | * Author: Wu Zhangjin, wuzj@lemote.com | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | */ | ||
15 | |||
16 | #include <cs5536/cs5536.h> | ||
17 | #include <cs5536/cs5536_pci.h> | ||
18 | |||
19 | void pci_acc_write_reg(int reg, u32 value) | ||
20 | { | ||
21 | u32 hi = 0, lo = value; | ||
22 | |||
23 | switch (reg) { | ||
24 | case PCI_COMMAND: | ||
25 | _rdmsr(GLIU_MSR_REG(GLIU_PAE), &hi, &lo); | ||
26 | if (value & PCI_COMMAND_MASTER) | ||
27 | lo |= (0x03 << 8); | ||
28 | else | ||
29 | lo &= ~(0x03 << 8); | ||
30 | _wrmsr(GLIU_MSR_REG(GLIU_PAE), hi, lo); | ||
31 | break; | ||
32 | case PCI_STATUS: | ||
33 | if (value & PCI_STATUS_PARITY) { | ||
34 | _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo); | ||
35 | if (lo & SB_PARE_ERR_FLAG) { | ||
36 | lo = (lo & 0x0000ffff) | SB_PARE_ERR_FLAG; | ||
37 | _wrmsr(SB_MSR_REG(SB_ERROR), hi, lo); | ||
38 | } | ||
39 | } | ||
40 | break; | ||
41 | case PCI_BAR0_REG: | ||
42 | if (value == PCI_BAR_RANGE_MASK) { | ||
43 | _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo); | ||
44 | lo |= SOFT_BAR_ACC_FLAG; | ||
45 | _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo); | ||
46 | } else if (value & 0x01) { | ||
47 | value &= 0xfffffffc; | ||
48 | hi = 0xA0000000 | ((value & 0x000ff000) >> 12); | ||
49 | lo = 0x000fff80 | ((value & 0x00000fff) << 20); | ||
50 | _wrmsr(GLIU_MSR_REG(GLIU_IOD_BM1), hi, lo); | ||
51 | } | ||
52 | break; | ||
53 | case PCI_ACC_INT_REG: | ||
54 | _rdmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), &hi, &lo); | ||
55 | /* disable all the usb interrupt in PIC */ | ||
56 | lo &= ~(0xf << PIC_YSEL_LOW_ACC_SHIFT); | ||
57 | if (value) /* enable all the acc interrupt in PIC */ | ||
58 | lo |= (CS5536_ACC_INTR << PIC_YSEL_LOW_ACC_SHIFT); | ||
59 | _wrmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), hi, lo); | ||
60 | break; | ||
61 | default: | ||
62 | break; | ||
63 | } | ||
64 | } | ||
65 | |||
66 | u32 pci_acc_read_reg(int reg) | ||
67 | { | ||
68 | u32 hi, lo; | ||
69 | u32 conf_data = 0; | ||
70 | |||
71 | switch (reg) { | ||
72 | case PCI_VENDOR_ID: | ||
73 | conf_data = | ||
74 | CFG_PCI_VENDOR_ID(CS5536_ACC_DEVICE_ID, CS5536_VENDOR_ID); | ||
75 | break; | ||
76 | case PCI_COMMAND: | ||
77 | _rdmsr(GLIU_MSR_REG(GLIU_IOD_BM1), &hi, &lo); | ||
78 | if (((lo & 0xfff00000) || (hi & 0x000000ff)) | ||
79 | && ((hi & 0xf0000000) == 0xa0000000)) | ||
80 | conf_data |= PCI_COMMAND_IO; | ||
81 | _rdmsr(GLIU_MSR_REG(GLIU_PAE), &hi, &lo); | ||
82 | if ((lo & 0x300) == 0x300) | ||
83 | conf_data |= PCI_COMMAND_MASTER; | ||
84 | break; | ||
85 | case PCI_STATUS: | ||
86 | conf_data |= PCI_STATUS_66MHZ; | ||
87 | conf_data |= PCI_STATUS_FAST_BACK; | ||
88 | _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo); | ||
89 | if (lo & SB_PARE_ERR_FLAG) | ||
90 | conf_data |= PCI_STATUS_PARITY; | ||
91 | conf_data |= PCI_STATUS_DEVSEL_MEDIUM; | ||
92 | break; | ||
93 | case PCI_CLASS_REVISION: | ||
94 | _rdmsr(ACC_MSR_REG(ACC_CAP), &hi, &lo); | ||
95 | conf_data = lo & 0x000000ff; | ||
96 | conf_data |= (CS5536_ACC_CLASS_CODE << 8); | ||
97 | break; | ||
98 | case PCI_CACHE_LINE_SIZE: | ||
99 | conf_data = | ||
100 | CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE, | ||
101 | PCI_NORMAL_LATENCY_TIMER); | ||
102 | break; | ||
103 | case PCI_BAR0_REG: | ||
104 | _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo); | ||
105 | if (lo & SOFT_BAR_ACC_FLAG) { | ||
106 | conf_data = CS5536_ACC_RANGE | | ||
107 | PCI_BASE_ADDRESS_SPACE_IO; | ||
108 | lo &= ~SOFT_BAR_ACC_FLAG; | ||
109 | _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo); | ||
110 | } else { | ||
111 | _rdmsr(GLIU_MSR_REG(GLIU_IOD_BM1), &hi, &lo); | ||
112 | conf_data = (hi & 0x000000ff) << 12; | ||
113 | conf_data |= (lo & 0xfff00000) >> 20; | ||
114 | conf_data |= 0x01; | ||
115 | conf_data &= ~0x02; | ||
116 | } | ||
117 | break; | ||
118 | case PCI_CARDBUS_CIS: | ||
119 | conf_data = PCI_CARDBUS_CIS_POINTER; | ||
120 | break; | ||
121 | case PCI_SUBSYSTEM_VENDOR_ID: | ||
122 | conf_data = | ||
123 | CFG_PCI_VENDOR_ID(CS5536_ACC_SUB_ID, CS5536_SUB_VENDOR_ID); | ||
124 | break; | ||
125 | case PCI_ROM_ADDRESS: | ||
126 | conf_data = PCI_EXPANSION_ROM_BAR; | ||
127 | break; | ||
128 | case PCI_CAPABILITY_LIST: | ||
129 | conf_data = PCI_CAPLIST_USB_POINTER; | ||
130 | break; | ||
131 | case PCI_INTERRUPT_LINE: | ||
132 | conf_data = | ||
133 | CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_ACC_INTR); | ||
134 | break; | ||
135 | default: | ||
136 | break; | ||
137 | } | ||
138 | |||
139 | return conf_data; | ||
140 | } | ||
diff --git a/arch/mips/loongson/common/cs5536/cs5536_ehci.c b/arch/mips/loongson/common/cs5536/cs5536_ehci.c new file mode 100644 index 000000000000..74f9c59d36af --- /dev/null +++ b/arch/mips/loongson/common/cs5536/cs5536_ehci.c | |||
@@ -0,0 +1,158 @@ | |||
1 | /* | ||
2 | * the EHCI Virtual Support Module of AMD CS5536 | ||
3 | * | ||
4 | * Copyright (C) 2007 Lemote, Inc. | ||
5 | * Author : jlliu, liujl@lemote.com | ||
6 | * | ||
7 | * Copyright (C) 2009 Lemote, Inc. | ||
8 | * Author: Wu Zhangjin, wuzj@lemote.com | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | */ | ||
15 | |||
16 | #include <cs5536/cs5536.h> | ||
17 | #include <cs5536/cs5536_pci.h> | ||
18 | |||
19 | void pci_ehci_write_reg(int reg, u32 value) | ||
20 | { | ||
21 | u32 hi = 0, lo = value; | ||
22 | |||
23 | switch (reg) { | ||
24 | case PCI_COMMAND: | ||
25 | _rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo); | ||
26 | if (value & PCI_COMMAND_MASTER) | ||
27 | hi |= PCI_COMMAND_MASTER; | ||
28 | else | ||
29 | hi &= ~PCI_COMMAND_MASTER; | ||
30 | |||
31 | if (value & PCI_COMMAND_MEMORY) | ||
32 | hi |= PCI_COMMAND_MEMORY; | ||
33 | else | ||
34 | hi &= ~PCI_COMMAND_MEMORY; | ||
35 | _wrmsr(USB_MSR_REG(USB_EHCI), hi, lo); | ||
36 | break; | ||
37 | case PCI_STATUS: | ||
38 | if (value & PCI_STATUS_PARITY) { | ||
39 | _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo); | ||
40 | if (lo & SB_PARE_ERR_FLAG) { | ||
41 | lo = (lo & 0x0000ffff) | SB_PARE_ERR_FLAG; | ||
42 | _wrmsr(SB_MSR_REG(SB_ERROR), hi, lo); | ||
43 | } | ||
44 | } | ||
45 | break; | ||
46 | case PCI_BAR0_REG: | ||
47 | if (value == PCI_BAR_RANGE_MASK) { | ||
48 | _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo); | ||
49 | lo |= SOFT_BAR_EHCI_FLAG; | ||
50 | _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo); | ||
51 | } else if ((value & 0x01) == 0x00) { | ||
52 | _wrmsr(USB_MSR_REG(USB_EHCI), hi, lo); | ||
53 | |||
54 | value &= 0xfffffff0; | ||
55 | hi = 0x40000000 | ((value & 0xff000000) >> 24); | ||
56 | lo = 0x000fffff | ((value & 0x00fff000) << 8); | ||
57 | _wrmsr(GLIU_MSR_REG(GLIU_P2D_BM4), hi, lo); | ||
58 | } | ||
59 | break; | ||
60 | case PCI_EHCI_LEGSMIEN_REG: | ||
61 | _rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo); | ||
62 | hi &= 0x003f0000; | ||
63 | hi |= (value & 0x3f) << 16; | ||
64 | _wrmsr(USB_MSR_REG(USB_EHCI), hi, lo); | ||
65 | break; | ||
66 | case PCI_EHCI_FLADJ_REG: | ||
67 | _rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo); | ||
68 | hi &= ~0x00003f00; | ||
69 | hi |= value & 0x00003f00; | ||
70 | _wrmsr(USB_MSR_REG(USB_EHCI), hi, lo); | ||
71 | break; | ||
72 | default: | ||
73 | break; | ||
74 | } | ||
75 | } | ||
76 | |||
77 | u32 pci_ehci_read_reg(int reg) | ||
78 | { | ||
79 | u32 conf_data = 0; | ||
80 | u32 hi, lo; | ||
81 | |||
82 | switch (reg) { | ||
83 | case PCI_VENDOR_ID: | ||
84 | conf_data = | ||
85 | CFG_PCI_VENDOR_ID(CS5536_EHCI_DEVICE_ID, CS5536_VENDOR_ID); | ||
86 | break; | ||
87 | case PCI_COMMAND: | ||
88 | _rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo); | ||
89 | if (hi & PCI_COMMAND_MASTER) | ||
90 | conf_data |= PCI_COMMAND_MASTER; | ||
91 | if (hi & PCI_COMMAND_MEMORY) | ||
92 | conf_data |= PCI_COMMAND_MEMORY; | ||
93 | break; | ||
94 | case PCI_STATUS: | ||
95 | conf_data |= PCI_STATUS_66MHZ; | ||
96 | conf_data |= PCI_STATUS_FAST_BACK; | ||
97 | _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo); | ||
98 | if (lo & SB_PARE_ERR_FLAG) | ||
99 | conf_data |= PCI_STATUS_PARITY; | ||
100 | conf_data |= PCI_STATUS_DEVSEL_MEDIUM; | ||
101 | break; | ||
102 | case PCI_CLASS_REVISION: | ||
103 | _rdmsr(USB_MSR_REG(USB_CAP), &hi, &lo); | ||
104 | conf_data = lo & 0x000000ff; | ||
105 | conf_data |= (CS5536_EHCI_CLASS_CODE << 8); | ||
106 | break; | ||
107 | case PCI_CACHE_LINE_SIZE: | ||
108 | conf_data = | ||
109 | CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE, | ||
110 | PCI_NORMAL_LATENCY_TIMER); | ||
111 | break; | ||
112 | case PCI_BAR0_REG: | ||
113 | _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo); | ||
114 | if (lo & SOFT_BAR_EHCI_FLAG) { | ||
115 | conf_data = CS5536_EHCI_RANGE | | ||
116 | PCI_BASE_ADDRESS_SPACE_MEMORY; | ||
117 | lo &= ~SOFT_BAR_EHCI_FLAG; | ||
118 | _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo); | ||
119 | } else { | ||
120 | _rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo); | ||
121 | conf_data = lo & 0xfffff000; | ||
122 | } | ||
123 | break; | ||
124 | case PCI_CARDBUS_CIS: | ||
125 | conf_data = PCI_CARDBUS_CIS_POINTER; | ||
126 | break; | ||
127 | case PCI_SUBSYSTEM_VENDOR_ID: | ||
128 | conf_data = | ||
129 | CFG_PCI_VENDOR_ID(CS5536_EHCI_SUB_ID, CS5536_SUB_VENDOR_ID); | ||
130 | break; | ||
131 | case PCI_ROM_ADDRESS: | ||
132 | conf_data = PCI_EXPANSION_ROM_BAR; | ||
133 | break; | ||
134 | case PCI_CAPABILITY_LIST: | ||
135 | conf_data = PCI_CAPLIST_USB_POINTER; | ||
136 | break; | ||
137 | case PCI_INTERRUPT_LINE: | ||
138 | conf_data = | ||
139 | CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_USB_INTR); | ||
140 | break; | ||
141 | case PCI_EHCI_LEGSMIEN_REG: | ||
142 | _rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo); | ||
143 | conf_data = (hi & 0x003f0000) >> 16; | ||
144 | break; | ||
145 | case PCI_EHCI_LEGSMISTS_REG: | ||
146 | _rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo); | ||
147 | conf_data = (hi & 0x3f000000) >> 24; | ||
148 | break; | ||
149 | case PCI_EHCI_FLADJ_REG: | ||
150 | _rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo); | ||
151 | conf_data = hi & 0x00003f00; | ||
152 | break; | ||
153 | default: | ||
154 | break; | ||
155 | } | ||
156 | |||
157 | return conf_data; | ||
158 | } | ||
diff --git a/arch/mips/loongson/common/cs5536/cs5536_ide.c b/arch/mips/loongson/common/cs5536/cs5536_ide.c new file mode 100644 index 000000000000..3f61594b3884 --- /dev/null +++ b/arch/mips/loongson/common/cs5536/cs5536_ide.c | |||
@@ -0,0 +1,179 @@ | |||
1 | /* | ||
2 | * the IDE Virtual Support Module of AMD CS5536 | ||
3 | * | ||
4 | * Copyright (C) 2007 Lemote, Inc. | ||
5 | * Author : jlliu, liujl@lemote.com | ||
6 | * | ||
7 | * Copyright (C) 2009 Lemote, Inc. | ||
8 | * Author: Wu Zhangjin, wuzj@lemote.com | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | */ | ||
15 | |||
16 | #include <cs5536/cs5536.h> | ||
17 | #include <cs5536/cs5536_pci.h> | ||
18 | |||
19 | void pci_ide_write_reg(int reg, u32 value) | ||
20 | { | ||
21 | u32 hi = 0, lo = value; | ||
22 | |||
23 | switch (reg) { | ||
24 | case PCI_COMMAND: | ||
25 | _rdmsr(GLIU_MSR_REG(GLIU_PAE), &hi, &lo); | ||
26 | if (value & PCI_COMMAND_MASTER) | ||
27 | lo |= (0x03 << 4); | ||
28 | else | ||
29 | lo &= ~(0x03 << 4); | ||
30 | _wrmsr(GLIU_MSR_REG(GLIU_PAE), hi, lo); | ||
31 | break; | ||
32 | case PCI_STATUS: | ||
33 | if (value & PCI_STATUS_PARITY) { | ||
34 | _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo); | ||
35 | if (lo & SB_PARE_ERR_FLAG) { | ||
36 | lo = (lo & 0x0000ffff) | SB_PARE_ERR_FLAG; | ||
37 | _wrmsr(SB_MSR_REG(SB_ERROR), hi, lo); | ||
38 | } | ||
39 | } | ||
40 | break; | ||
41 | case PCI_CACHE_LINE_SIZE: | ||
42 | value &= 0x0000ff00; | ||
43 | _rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo); | ||
44 | hi &= 0xffffff00; | ||
45 | hi |= (value >> 8); | ||
46 | _wrmsr(SB_MSR_REG(SB_CTRL), hi, lo); | ||
47 | break; | ||
48 | case PCI_BAR4_REG: | ||
49 | if (value == PCI_BAR_RANGE_MASK) { | ||
50 | _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo); | ||
51 | lo |= SOFT_BAR_IDE_FLAG; | ||
52 | _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo); | ||
53 | } else if (value & 0x01) { | ||
54 | lo = (value & 0xfffffff0) | 0x1; | ||
55 | _wrmsr(IDE_MSR_REG(IDE_IO_BAR), hi, lo); | ||
56 | |||
57 | value &= 0xfffffffc; | ||
58 | hi = 0x60000000 | ((value & 0x000ff000) >> 12); | ||
59 | lo = 0x000ffff0 | ((value & 0x00000fff) << 20); | ||
60 | _wrmsr(GLIU_MSR_REG(GLIU_IOD_BM2), hi, lo); | ||
61 | } | ||
62 | break; | ||
63 | case PCI_IDE_CFG_REG: | ||
64 | if (value == CS5536_IDE_FLASH_SIGNATURE) { | ||
65 | _rdmsr(DIVIL_MSR_REG(DIVIL_BALL_OPTS), &hi, &lo); | ||
66 | lo |= 0x01; | ||
67 | _wrmsr(DIVIL_MSR_REG(DIVIL_BALL_OPTS), hi, lo); | ||
68 | } else | ||
69 | _wrmsr(IDE_MSR_REG(IDE_CFG), hi, lo); | ||
70 | break; | ||
71 | case PCI_IDE_DTC_REG: | ||
72 | _wrmsr(IDE_MSR_REG(IDE_DTC), hi, lo); | ||
73 | break; | ||
74 | case PCI_IDE_CAST_REG: | ||
75 | _wrmsr(IDE_MSR_REG(IDE_CAST), hi, lo); | ||
76 | break; | ||
77 | case PCI_IDE_ETC_REG: | ||
78 | _wrmsr(IDE_MSR_REG(IDE_ETC), hi, lo); | ||
79 | break; | ||
80 | case PCI_IDE_PM_REG: | ||
81 | _wrmsr(IDE_MSR_REG(IDE_INTERNAL_PM), hi, lo); | ||
82 | break; | ||
83 | default: | ||
84 | break; | ||
85 | } | ||
86 | } | ||
87 | |||
88 | u32 pci_ide_read_reg(int reg) | ||
89 | { | ||
90 | u32 conf_data = 0; | ||
91 | u32 hi, lo; | ||
92 | |||
93 | switch (reg) { | ||
94 | case PCI_VENDOR_ID: | ||
95 | conf_data = | ||
96 | CFG_PCI_VENDOR_ID(CS5536_IDE_DEVICE_ID, CS5536_VENDOR_ID); | ||
97 | break; | ||
98 | case PCI_COMMAND: | ||
99 | _rdmsr(IDE_MSR_REG(IDE_IO_BAR), &hi, &lo); | ||
100 | if (lo & 0xfffffff0) | ||
101 | conf_data |= PCI_COMMAND_IO; | ||
102 | _rdmsr(GLIU_MSR_REG(GLIU_PAE), &hi, &lo); | ||
103 | if ((lo & 0x30) == 0x30) | ||
104 | conf_data |= PCI_COMMAND_MASTER; | ||
105 | break; | ||
106 | case PCI_STATUS: | ||
107 | conf_data |= PCI_STATUS_66MHZ; | ||
108 | conf_data |= PCI_STATUS_FAST_BACK; | ||
109 | _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo); | ||
110 | if (lo & SB_PARE_ERR_FLAG) | ||
111 | conf_data |= PCI_STATUS_PARITY; | ||
112 | conf_data |= PCI_STATUS_DEVSEL_MEDIUM; | ||
113 | break; | ||
114 | case PCI_CLASS_REVISION: | ||
115 | _rdmsr(IDE_MSR_REG(IDE_CAP), &hi, &lo); | ||
116 | conf_data = lo & 0x000000ff; | ||
117 | conf_data |= (CS5536_IDE_CLASS_CODE << 8); | ||
118 | break; | ||
119 | case PCI_CACHE_LINE_SIZE: | ||
120 | _rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo); | ||
121 | hi &= 0x000000f8; | ||
122 | conf_data = CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE, hi); | ||
123 | break; | ||
124 | case PCI_BAR4_REG: | ||
125 | _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo); | ||
126 | if (lo & SOFT_BAR_IDE_FLAG) { | ||
127 | conf_data = CS5536_IDE_RANGE | | ||
128 | PCI_BASE_ADDRESS_SPACE_IO; | ||
129 | lo &= ~SOFT_BAR_IDE_FLAG; | ||
130 | _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo); | ||
131 | } else { | ||
132 | _rdmsr(IDE_MSR_REG(IDE_IO_BAR), &hi, &lo); | ||
133 | conf_data = lo & 0xfffffff0; | ||
134 | conf_data |= 0x01; | ||
135 | conf_data &= ~0x02; | ||
136 | } | ||
137 | break; | ||
138 | case PCI_CARDBUS_CIS: | ||
139 | conf_data = PCI_CARDBUS_CIS_POINTER; | ||
140 | break; | ||
141 | case PCI_SUBSYSTEM_VENDOR_ID: | ||
142 | conf_data = | ||
143 | CFG_PCI_VENDOR_ID(CS5536_IDE_SUB_ID, CS5536_SUB_VENDOR_ID); | ||
144 | break; | ||
145 | case PCI_ROM_ADDRESS: | ||
146 | conf_data = PCI_EXPANSION_ROM_BAR; | ||
147 | break; | ||
148 | case PCI_CAPABILITY_LIST: | ||
149 | conf_data = PCI_CAPLIST_POINTER; | ||
150 | break; | ||
151 | case PCI_INTERRUPT_LINE: | ||
152 | conf_data = | ||
153 | CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_IDE_INTR); | ||
154 | break; | ||
155 | case PCI_IDE_CFG_REG: | ||
156 | _rdmsr(IDE_MSR_REG(IDE_CFG), &hi, &lo); | ||
157 | conf_data = lo; | ||
158 | break; | ||
159 | case PCI_IDE_DTC_REG: | ||
160 | _rdmsr(IDE_MSR_REG(IDE_DTC), &hi, &lo); | ||
161 | conf_data = lo; | ||
162 | break; | ||
163 | case PCI_IDE_CAST_REG: | ||
164 | _rdmsr(IDE_MSR_REG(IDE_CAST), &hi, &lo); | ||
165 | conf_data = lo; | ||
166 | break; | ||
167 | case PCI_IDE_ETC_REG: | ||
168 | _rdmsr(IDE_MSR_REG(IDE_ETC), &hi, &lo); | ||
169 | conf_data = lo; | ||
170 | case PCI_IDE_PM_REG: | ||
171 | _rdmsr(IDE_MSR_REG(IDE_INTERNAL_PM), &hi, &lo); | ||
172 | conf_data = lo; | ||
173 | break; | ||
174 | default: | ||
175 | break; | ||
176 | } | ||
177 | |||
178 | return conf_data; | ||
179 | } | ||
diff --git a/arch/mips/loongson/common/cs5536/cs5536_isa.c b/arch/mips/loongson/common/cs5536/cs5536_isa.c new file mode 100644 index 000000000000..b6f17f538e48 --- /dev/null +++ b/arch/mips/loongson/common/cs5536/cs5536_isa.c | |||
@@ -0,0 +1,316 @@ | |||
1 | /* | ||
2 | * the ISA Virtual Support Module of AMD CS5536 | ||
3 | * | ||
4 | * Copyright (C) 2007 Lemote, Inc. | ||
5 | * Author : jlliu, liujl@lemote.com | ||
6 | * | ||
7 | * Copyright (C) 2009 Lemote, Inc. | ||
8 | * Author: Wu Zhangjin, wuzj@lemote.com | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | */ | ||
15 | |||
16 | #include <cs5536/cs5536.h> | ||
17 | #include <cs5536/cs5536_pci.h> | ||
18 | |||
19 | /* common variables for PCI_ISA_READ/WRITE_BAR */ | ||
20 | static const u32 divil_msr_reg[6] = { | ||
21 | DIVIL_MSR_REG(DIVIL_LBAR_SMB), DIVIL_MSR_REG(DIVIL_LBAR_GPIO), | ||
22 | DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), DIVIL_MSR_REG(DIVIL_LBAR_IRQ), | ||
23 | DIVIL_MSR_REG(DIVIL_LBAR_PMS), DIVIL_MSR_REG(DIVIL_LBAR_ACPI), | ||
24 | }; | ||
25 | |||
26 | static const u32 soft_bar_flag[6] = { | ||
27 | SOFT_BAR_SMB_FLAG, SOFT_BAR_GPIO_FLAG, SOFT_BAR_MFGPT_FLAG, | ||
28 | SOFT_BAR_IRQ_FLAG, SOFT_BAR_PMS_FLAG, SOFT_BAR_ACPI_FLAG, | ||
29 | }; | ||
30 | |||
31 | static const u32 sb_msr_reg[6] = { | ||
32 | SB_MSR_REG(SB_R0), SB_MSR_REG(SB_R1), SB_MSR_REG(SB_R2), | ||
33 | SB_MSR_REG(SB_R3), SB_MSR_REG(SB_R4), SB_MSR_REG(SB_R5), | ||
34 | }; | ||
35 | |||
36 | static const u32 bar_space_range[6] = { | ||
37 | CS5536_SMB_RANGE, CS5536_GPIO_RANGE, CS5536_MFGPT_RANGE, | ||
38 | CS5536_IRQ_RANGE, CS5536_PMS_RANGE, CS5536_ACPI_RANGE, | ||
39 | }; | ||
40 | |||
41 | static const int bar_space_len[6] = { | ||
42 | CS5536_SMB_LENGTH, CS5536_GPIO_LENGTH, CS5536_MFGPT_LENGTH, | ||
43 | CS5536_IRQ_LENGTH, CS5536_PMS_LENGTH, CS5536_ACPI_LENGTH, | ||
44 | }; | ||
45 | |||
46 | /* | ||
47 | * enable the divil module bar space. | ||
48 | * | ||
49 | * For all the DIVIL module LBAR, you should control the DIVIL LBAR reg | ||
50 | * and the RCONFx(0~5) reg to use the modules. | ||
51 | */ | ||
52 | static void divil_lbar_enable(void) | ||
53 | { | ||
54 | u32 hi, lo; | ||
55 | int offset; | ||
56 | |||
57 | /* | ||
58 | * The DIVIL IRQ is not used yet. and make the RCONF0 reserved. | ||
59 | */ | ||
60 | |||
61 | for (offset = DIVIL_LBAR_SMB; offset <= DIVIL_LBAR_PMS; offset++) { | ||
62 | _rdmsr(DIVIL_MSR_REG(offset), &hi, &lo); | ||
63 | hi |= 0x01; | ||
64 | _wrmsr(DIVIL_MSR_REG(DIVIL_LBAR_SMB), hi, lo); | ||
65 | } | ||
66 | } | ||
67 | |||
68 | /* | ||
69 | * disable the divil module bar space. | ||
70 | */ | ||
71 | static void divil_lbar_disable(void) | ||
72 | { | ||
73 | u32 hi, lo; | ||
74 | int offset; | ||
75 | |||
76 | for (offset = DIVIL_LBAR_SMB; offset <= DIVIL_LBAR_PMS; offset++) { | ||
77 | _rdmsr(DIVIL_MSR_REG(offset), &hi, &lo); | ||
78 | hi &= ~0x01; | ||
79 | _wrmsr(DIVIL_MSR_REG(DIVIL_LBAR_SMB), hi, lo); | ||
80 | } | ||
81 | } | ||
82 | |||
83 | /* | ||
84 | * BAR write: write value to the n BAR | ||
85 | */ | ||
86 | |||
87 | void pci_isa_write_bar(int n, u32 value) | ||
88 | { | ||
89 | u32 hi = 0, lo = value; | ||
90 | |||
91 | if (value == PCI_BAR_RANGE_MASK) { | ||
92 | _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo); | ||
93 | lo |= soft_bar_flag[n]; | ||
94 | _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo); | ||
95 | } else if (value & 0x01) { | ||
96 | /* NATIVE reg */ | ||
97 | hi = 0x0000f001; | ||
98 | lo &= bar_space_range[n]; | ||
99 | _wrmsr(divil_msr_reg[n], hi, lo); | ||
100 | |||
101 | /* RCONFx is 4bytes in units for I/O space */ | ||
102 | hi = ((value & 0x000ffffc) << 12) | | ||
103 | ((bar_space_len[n] - 4) << 12) | 0x01; | ||
104 | lo = ((value & 0x000ffffc) << 12) | 0x01; | ||
105 | _wrmsr(sb_msr_reg[n], hi, lo); | ||
106 | } | ||
107 | } | ||
108 | |||
109 | /* | ||
110 | * BAR read: read the n BAR | ||
111 | */ | ||
112 | |||
113 | u32 pci_isa_read_bar(int n) | ||
114 | { | ||
115 | u32 conf_data = 0; | ||
116 | u32 hi, lo; | ||
117 | |||
118 | _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo); | ||
119 | if (lo & soft_bar_flag[n]) { | ||
120 | conf_data = bar_space_range[n] | PCI_BASE_ADDRESS_SPACE_IO; | ||
121 | lo &= ~soft_bar_flag[n]; | ||
122 | _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo); | ||
123 | } else { | ||
124 | _rdmsr(divil_msr_reg[n], &hi, &lo); | ||
125 | conf_data = lo & bar_space_range[n]; | ||
126 | conf_data |= 0x01; | ||
127 | conf_data &= ~0x02; | ||
128 | } | ||
129 | return conf_data; | ||
130 | } | ||
131 | |||
132 | /* | ||
133 | * isa_write: ISA write transfer | ||
134 | * | ||
135 | * We assume that this is not a bus master transfer. | ||
136 | */ | ||
137 | void pci_isa_write_reg(int reg, u32 value) | ||
138 | { | ||
139 | u32 hi = 0, lo = value; | ||
140 | u32 temp; | ||
141 | |||
142 | switch (reg) { | ||
143 | case PCI_COMMAND: | ||
144 | if (value & PCI_COMMAND_IO) | ||
145 | divil_lbar_enable(); | ||
146 | else | ||
147 | divil_lbar_disable(); | ||
148 | break; | ||
149 | case PCI_STATUS: | ||
150 | _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo); | ||
151 | temp = lo & 0x0000ffff; | ||
152 | if ((value & PCI_STATUS_SIG_TARGET_ABORT) && | ||
153 | (lo & SB_TAS_ERR_EN)) | ||
154 | temp |= SB_TAS_ERR_FLAG; | ||
155 | |||
156 | if ((value & PCI_STATUS_REC_TARGET_ABORT) && | ||
157 | (lo & SB_TAR_ERR_EN)) | ||
158 | temp |= SB_TAR_ERR_FLAG; | ||
159 | |||
160 | if ((value & PCI_STATUS_REC_MASTER_ABORT) | ||
161 | && (lo & SB_MAR_ERR_EN)) | ||
162 | temp |= SB_MAR_ERR_FLAG; | ||
163 | |||
164 | if ((value & PCI_STATUS_DETECTED_PARITY) | ||
165 | && (lo & SB_PARE_ERR_EN)) | ||
166 | temp |= SB_PARE_ERR_FLAG; | ||
167 | |||
168 | lo = temp; | ||
169 | _wrmsr(SB_MSR_REG(SB_ERROR), hi, lo); | ||
170 | break; | ||
171 | case PCI_CACHE_LINE_SIZE: | ||
172 | value &= 0x0000ff00; | ||
173 | _rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo); | ||
174 | hi &= 0xffffff00; | ||
175 | hi |= (value >> 8); | ||
176 | _wrmsr(SB_MSR_REG(SB_CTRL), hi, lo); | ||
177 | break; | ||
178 | case PCI_BAR0_REG: | ||
179 | pci_isa_write_bar(0, value); | ||
180 | break; | ||
181 | case PCI_BAR1_REG: | ||
182 | pci_isa_write_bar(1, value); | ||
183 | break; | ||
184 | case PCI_BAR2_REG: | ||
185 | pci_isa_write_bar(2, value); | ||
186 | break; | ||
187 | case PCI_BAR3_REG: | ||
188 | pci_isa_write_bar(3, value); | ||
189 | break; | ||
190 | case PCI_BAR4_REG: | ||
191 | pci_isa_write_bar(4, value); | ||
192 | break; | ||
193 | case PCI_BAR5_REG: | ||
194 | pci_isa_write_bar(5, value); | ||
195 | break; | ||
196 | case PCI_UART1_INT_REG: | ||
197 | _rdmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), &hi, &lo); | ||
198 | /* disable uart1 interrupt in PIC */ | ||
199 | lo &= ~(0xf << 24); | ||
200 | if (value) /* enable uart1 interrupt in PIC */ | ||
201 | lo |= (CS5536_UART1_INTR << 24); | ||
202 | _wrmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), hi, lo); | ||
203 | break; | ||
204 | case PCI_UART2_INT_REG: | ||
205 | _rdmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), &hi, &lo); | ||
206 | /* disable uart2 interrupt in PIC */ | ||
207 | lo &= ~(0xf << 28); | ||
208 | if (value) /* enable uart2 interrupt in PIC */ | ||
209 | lo |= (CS5536_UART2_INTR << 28); | ||
210 | _wrmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), hi, lo); | ||
211 | break; | ||
212 | case PCI_ISA_FIXUP_REG: | ||
213 | if (value) { | ||
214 | /* enable the TARGET ABORT/MASTER ABORT etc. */ | ||
215 | _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo); | ||
216 | lo |= 0x00000063; | ||
217 | _wrmsr(SB_MSR_REG(SB_ERROR), hi, lo); | ||
218 | } | ||
219 | |||
220 | default: | ||
221 | /* ALL OTHER PCI CONFIG SPACE HEADER IS NOT IMPLEMENTED. */ | ||
222 | break; | ||
223 | } | ||
224 | } | ||
225 | |||
226 | /* | ||
227 | * isa_read: ISA read transfers | ||
228 | * | ||
229 | * We assume that this is not a bus master transfer. | ||
230 | */ | ||
231 | u32 pci_isa_read_reg(int reg) | ||
232 | { | ||
233 | u32 conf_data = 0; | ||
234 | u32 hi, lo; | ||
235 | |||
236 | switch (reg) { | ||
237 | case PCI_VENDOR_ID: | ||
238 | conf_data = | ||
239 | CFG_PCI_VENDOR_ID(CS5536_ISA_DEVICE_ID, CS5536_VENDOR_ID); | ||
240 | break; | ||
241 | case PCI_COMMAND: | ||
242 | /* we just check the first LBAR for the IO enable bit, */ | ||
243 | /* maybe we should changed later. */ | ||
244 | _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_SMB), &hi, &lo); | ||
245 | if (hi & 0x01) | ||
246 | conf_data |= PCI_COMMAND_IO; | ||
247 | break; | ||
248 | case PCI_STATUS: | ||
249 | conf_data |= PCI_STATUS_66MHZ; | ||
250 | conf_data |= PCI_STATUS_DEVSEL_MEDIUM; | ||
251 | conf_data |= PCI_STATUS_FAST_BACK; | ||
252 | |||
253 | _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo); | ||
254 | if (lo & SB_TAS_ERR_FLAG) | ||
255 | conf_data |= PCI_STATUS_SIG_TARGET_ABORT; | ||
256 | if (lo & SB_TAR_ERR_FLAG) | ||
257 | conf_data |= PCI_STATUS_REC_TARGET_ABORT; | ||
258 | if (lo & SB_MAR_ERR_FLAG) | ||
259 | conf_data |= PCI_STATUS_REC_MASTER_ABORT; | ||
260 | if (lo & SB_PARE_ERR_FLAG) | ||
261 | conf_data |= PCI_STATUS_DETECTED_PARITY; | ||
262 | break; | ||
263 | case PCI_CLASS_REVISION: | ||
264 | _rdmsr(GLCP_MSR_REG(GLCP_CHIP_REV_ID), &hi, &lo); | ||
265 | conf_data = lo & 0x000000ff; | ||
266 | conf_data |= (CS5536_ISA_CLASS_CODE << 8); | ||
267 | break; | ||
268 | case PCI_CACHE_LINE_SIZE: | ||
269 | _rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo); | ||
270 | hi &= 0x000000f8; | ||
271 | conf_data = CFG_PCI_CACHE_LINE_SIZE(PCI_BRIDGE_HEADER_TYPE, hi); | ||
272 | break; | ||
273 | /* | ||
274 | * we only use the LBAR of DIVIL, no RCONF used. | ||
275 | * all of them are IO space. | ||
276 | */ | ||
277 | case PCI_BAR0_REG: | ||
278 | return pci_isa_read_bar(0); | ||
279 | break; | ||
280 | case PCI_BAR1_REG: | ||
281 | return pci_isa_read_bar(1); | ||
282 | break; | ||
283 | case PCI_BAR2_REG: | ||
284 | return pci_isa_read_bar(2); | ||
285 | break; | ||
286 | case PCI_BAR3_REG: | ||
287 | break; | ||
288 | case PCI_BAR4_REG: | ||
289 | return pci_isa_read_bar(4); | ||
290 | break; | ||
291 | case PCI_BAR5_REG: | ||
292 | return pci_isa_read_bar(5); | ||
293 | break; | ||
294 | case PCI_CARDBUS_CIS: | ||
295 | conf_data = PCI_CARDBUS_CIS_POINTER; | ||
296 | break; | ||
297 | case PCI_SUBSYSTEM_VENDOR_ID: | ||
298 | conf_data = | ||
299 | CFG_PCI_VENDOR_ID(CS5536_ISA_SUB_ID, CS5536_SUB_VENDOR_ID); | ||
300 | break; | ||
301 | case PCI_ROM_ADDRESS: | ||
302 | conf_data = PCI_EXPANSION_ROM_BAR; | ||
303 | break; | ||
304 | case PCI_CAPABILITY_LIST: | ||
305 | conf_data = PCI_CAPLIST_POINTER; | ||
306 | break; | ||
307 | case PCI_INTERRUPT_LINE: | ||
308 | /* no interrupt used here */ | ||
309 | conf_data = CFG_PCI_INTERRUPT_LINE(0x00, 0x00); | ||
310 | break; | ||
311 | default: | ||
312 | break; | ||
313 | } | ||
314 | |||
315 | return conf_data; | ||
316 | } | ||
diff --git a/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c b/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c new file mode 100644 index 000000000000..6cb44dbaeec2 --- /dev/null +++ b/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c | |||
@@ -0,0 +1,217 @@ | |||
1 | /* | ||
2 | * CS5536 General timer functions | ||
3 | * | ||
4 | * Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology | ||
5 | * Author: Yanhua, yanh@lemote.com | ||
6 | * | ||
7 | * Copyright (C) 2009 Lemote Inc. | ||
8 | * Author: Wu zhangjin, wuzj@lemote.com | ||
9 | * | ||
10 | * Reference: AMD Geode(TM) CS5536 Companion Device Data Book | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | */ | ||
17 | |||
18 | #include <linux/io.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/jiffies.h> | ||
22 | #include <linux/spinlock.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/clockchips.h> | ||
25 | |||
26 | #include <asm/time.h> | ||
27 | |||
28 | #include <cs5536/cs5536_mfgpt.h> | ||
29 | |||
30 | DEFINE_SPINLOCK(mfgpt_lock); | ||
31 | EXPORT_SYMBOL(mfgpt_lock); | ||
32 | |||
33 | static u32 mfgpt_base; | ||
34 | |||
35 | /* | ||
36 | * Initialize the MFGPT timer. | ||
37 | * | ||
38 | * This is also called after resume to bring the MFGPT into operation again. | ||
39 | */ | ||
40 | |||
41 | /* disable counter */ | ||
42 | void disable_mfgpt0_counter(void) | ||
43 | { | ||
44 | outw(inw(MFGPT0_SETUP) & 0x7fff, MFGPT0_SETUP); | ||
45 | } | ||
46 | EXPORT_SYMBOL(disable_mfgpt0_counter); | ||
47 | |||
48 | /* enable counter, comparator2 to event mode, 14.318MHz clock */ | ||
49 | void enable_mfgpt0_counter(void) | ||
50 | { | ||
51 | outw(0xe310, MFGPT0_SETUP); | ||
52 | } | ||
53 | EXPORT_SYMBOL(enable_mfgpt0_counter); | ||
54 | |||
55 | static void init_mfgpt_timer(enum clock_event_mode mode, | ||
56 | struct clock_event_device *evt) | ||
57 | { | ||
58 | spin_lock(&mfgpt_lock); | ||
59 | |||
60 | switch (mode) { | ||
61 | case CLOCK_EVT_MODE_PERIODIC: | ||
62 | outw(COMPARE, MFGPT0_CMP2); /* set comparator2 */ | ||
63 | outw(0, MFGPT0_CNT); /* set counter to 0 */ | ||
64 | enable_mfgpt0_counter(); | ||
65 | break; | ||
66 | |||
67 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
68 | case CLOCK_EVT_MODE_UNUSED: | ||
69 | if (evt->mode == CLOCK_EVT_MODE_PERIODIC || | ||
70 | evt->mode == CLOCK_EVT_MODE_ONESHOT) | ||
71 | disable_mfgpt0_counter(); | ||
72 | break; | ||
73 | |||
74 | case CLOCK_EVT_MODE_ONESHOT: | ||
75 | /* The oneshot mode have very high deviation, Not use it! */ | ||
76 | break; | ||
77 | |||
78 | case CLOCK_EVT_MODE_RESUME: | ||
79 | /* Nothing to do here */ | ||
80 | break; | ||
81 | } | ||
82 | spin_unlock(&mfgpt_lock); | ||
83 | } | ||
84 | |||
85 | static struct clock_event_device mfgpt_clockevent = { | ||
86 | .name = "mfgpt", | ||
87 | .features = CLOCK_EVT_FEAT_PERIODIC, | ||
88 | .set_mode = init_mfgpt_timer, | ||
89 | .irq = CS5536_MFGPT_INTR, | ||
90 | }; | ||
91 | |||
92 | static irqreturn_t timer_interrupt(int irq, void *dev_id) | ||
93 | { | ||
94 | u32 basehi; | ||
95 | |||
96 | /* | ||
97 | * get MFGPT base address | ||
98 | * | ||
99 | * NOTE: do not remove me, it's need for the value of mfgpt_base is | ||
100 | * variable | ||
101 | */ | ||
102 | _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &basehi, &mfgpt_base); | ||
103 | |||
104 | /* ack */ | ||
105 | outw(inw(MFGPT0_SETUP) | 0x4000, MFGPT0_SETUP); | ||
106 | |||
107 | mfgpt_clockevent.event_handler(&mfgpt_clockevent); | ||
108 | |||
109 | return IRQ_HANDLED; | ||
110 | } | ||
111 | |||
112 | static struct irqaction irq5 = { | ||
113 | .handler = timer_interrupt, | ||
114 | .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER, | ||
115 | .name = "timer" | ||
116 | }; | ||
117 | |||
118 | /* | ||
119 | * Initialize the conversion factor and the min/max deltas of the clock event | ||
120 | * structure and register the clock event source with the framework. | ||
121 | */ | ||
122 | void __init setup_mfgpt0_timer(void) | ||
123 | { | ||
124 | u32 basehi; | ||
125 | struct clock_event_device *cd = &mfgpt_clockevent; | ||
126 | unsigned int cpu = smp_processor_id(); | ||
127 | |||
128 | cd->cpumask = cpumask_of(cpu); | ||
129 | clockevent_set_clock(cd, MFGPT_TICK_RATE); | ||
130 | cd->max_delta_ns = clockevent_delta2ns(0xffff, cd); | ||
131 | cd->min_delta_ns = clockevent_delta2ns(0xf, cd); | ||
132 | |||
133 | /* Enable MFGPT0 Comparator 2 Output to the Interrupt Mapper */ | ||
134 | _wrmsr(DIVIL_MSR_REG(MFGPT_IRQ), 0, 0x100); | ||
135 | |||
136 | /* Enable Interrupt Gate 5 */ | ||
137 | _wrmsr(DIVIL_MSR_REG(PIC_ZSEL_LOW), 0, 0x50000); | ||
138 | |||
139 | /* get MFGPT base address */ | ||
140 | _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &basehi, &mfgpt_base); | ||
141 | |||
142 | clockevents_register_device(cd); | ||
143 | |||
144 | setup_irq(CS5536_MFGPT_INTR, &irq5); | ||
145 | } | ||
146 | |||
147 | /* | ||
148 | * Since the MFGPT overflows every tick, its not very useful | ||
149 | * to just read by itself. So use jiffies to emulate a free | ||
150 | * running counter: | ||
151 | */ | ||
152 | static cycle_t mfgpt_read(struct clocksource *cs) | ||
153 | { | ||
154 | unsigned long flags; | ||
155 | int count; | ||
156 | u32 jifs; | ||
157 | static int old_count; | ||
158 | static u32 old_jifs; | ||
159 | |||
160 | spin_lock_irqsave(&mfgpt_lock, flags); | ||
161 | /* | ||
162 | * Although our caller may have the read side of xtime_lock, | ||
163 | * this is now a seqlock, and we are cheating in this routine | ||
164 | * by having side effects on state that we cannot undo if | ||
165 | * there is a collision on the seqlock and our caller has to | ||
166 | * retry. (Namely, old_jifs and old_count.) So we must treat | ||
167 | * jiffies as volatile despite the lock. We read jiffies | ||
168 | * before latching the timer count to guarantee that although | ||
169 | * the jiffies value might be older than the count (that is, | ||
170 | * the counter may underflow between the last point where | ||
171 | * jiffies was incremented and the point where we latch the | ||
172 | * count), it cannot be newer. | ||
173 | */ | ||
174 | jifs = jiffies; | ||
175 | /* read the count */ | ||
176 | count = inw(MFGPT0_CNT); | ||
177 | |||
178 | /* | ||
179 | * It's possible for count to appear to go the wrong way for this | ||
180 | * reason: | ||
181 | * | ||
182 | * The timer counter underflows, but we haven't handled the resulting | ||
183 | * interrupt and incremented jiffies yet. | ||
184 | * | ||
185 | * Previous attempts to handle these cases intelligently were buggy, so | ||
186 | * we just do the simple thing now. | ||
187 | */ | ||
188 | if (count < old_count && jifs == old_jifs) | ||
189 | count = old_count; | ||
190 | |||
191 | old_count = count; | ||
192 | old_jifs = jifs; | ||
193 | |||
194 | spin_unlock_irqrestore(&mfgpt_lock, flags); | ||
195 | |||
196 | return (cycle_t) (jifs * COMPARE) + count; | ||
197 | } | ||
198 | |||
199 | static struct clocksource clocksource_mfgpt = { | ||
200 | .name = "mfgpt", | ||
201 | .rating = 120, /* Functional for real use, but not desired */ | ||
202 | .read = mfgpt_read, | ||
203 | .mask = CLOCKSOURCE_MASK(32), | ||
204 | .mult = 0, | ||
205 | .shift = 22, | ||
206 | }; | ||
207 | |||
208 | int __init init_mfgpt_clocksource(void) | ||
209 | { | ||
210 | if (num_possible_cpus() > 1) /* MFGPT does not scale! */ | ||
211 | return 0; | ||
212 | |||
213 | clocksource_mfgpt.mult = clocksource_hz2mult(MFGPT_TICK_RATE, 22); | ||
214 | return clocksource_register(&clocksource_mfgpt); | ||
215 | } | ||
216 | |||
217 | arch_initcall(init_mfgpt_clocksource); | ||
diff --git a/arch/mips/loongson/common/cs5536/cs5536_ohci.c b/arch/mips/loongson/common/cs5536/cs5536_ohci.c new file mode 100644 index 000000000000..8fdb02b6e90f --- /dev/null +++ b/arch/mips/loongson/common/cs5536/cs5536_ohci.c | |||
@@ -0,0 +1,147 @@ | |||
1 | /* | ||
2 | * the OHCI Virtual Support Module of AMD CS5536 | ||
3 | * | ||
4 | * Copyright (C) 2007 Lemote, Inc. | ||
5 | * Author : jlliu, liujl@lemote.com | ||
6 | * | ||
7 | * Copyright (C) 2009 Lemote, Inc. | ||
8 | * Author: Wu Zhangjin, wuzj@lemote.com | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | */ | ||
15 | |||
16 | #include <cs5536/cs5536.h> | ||
17 | #include <cs5536/cs5536_pci.h> | ||
18 | |||
19 | void pci_ohci_write_reg(int reg, u32 value) | ||
20 | { | ||
21 | u32 hi = 0, lo = value; | ||
22 | |||
23 | switch (reg) { | ||
24 | case PCI_COMMAND: | ||
25 | _rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo); | ||
26 | if (value & PCI_COMMAND_MASTER) | ||
27 | hi |= PCI_COMMAND_MASTER; | ||
28 | else | ||
29 | hi &= ~PCI_COMMAND_MASTER; | ||
30 | |||
31 | if (value & PCI_COMMAND_MEMORY) | ||
32 | hi |= PCI_COMMAND_MEMORY; | ||
33 | else | ||
34 | hi &= ~PCI_COMMAND_MEMORY; | ||
35 | _wrmsr(USB_MSR_REG(USB_OHCI), hi, lo); | ||
36 | break; | ||
37 | case PCI_STATUS: | ||
38 | if (value & PCI_STATUS_PARITY) { | ||
39 | _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo); | ||
40 | if (lo & SB_PARE_ERR_FLAG) { | ||
41 | lo = (lo & 0x0000ffff) | SB_PARE_ERR_FLAG; | ||
42 | _wrmsr(SB_MSR_REG(SB_ERROR), hi, lo); | ||
43 | } | ||
44 | } | ||
45 | break; | ||
46 | case PCI_BAR0_REG: | ||
47 | if (value == PCI_BAR_RANGE_MASK) { | ||
48 | _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo); | ||
49 | lo |= SOFT_BAR_OHCI_FLAG; | ||
50 | _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo); | ||
51 | } else if ((value & 0x01) == 0x00) { | ||
52 | _wrmsr(USB_MSR_REG(USB_OHCI), hi, lo); | ||
53 | |||
54 | value &= 0xfffffff0; | ||
55 | hi = 0x40000000 | ((value & 0xff000000) >> 24); | ||
56 | lo = 0x000fffff | ((value & 0x00fff000) << 8); | ||
57 | _wrmsr(GLIU_MSR_REG(GLIU_P2D_BM3), hi, lo); | ||
58 | } | ||
59 | break; | ||
60 | case PCI_OHCI_INT_REG: | ||
61 | _rdmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), &hi, &lo); | ||
62 | lo &= ~(0xf << PIC_YSEL_LOW_USB_SHIFT); | ||
63 | if (value) /* enable all the usb interrupt in PIC */ | ||
64 | lo |= (CS5536_USB_INTR << PIC_YSEL_LOW_USB_SHIFT); | ||
65 | _wrmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), hi, lo); | ||
66 | break; | ||
67 | default: | ||
68 | break; | ||
69 | } | ||
70 | } | ||
71 | |||
72 | u32 pci_ohci_read_reg(int reg) | ||
73 | { | ||
74 | u32 conf_data = 0; | ||
75 | u32 hi, lo; | ||
76 | |||
77 | switch (reg) { | ||
78 | case PCI_VENDOR_ID: | ||
79 | conf_data = | ||
80 | CFG_PCI_VENDOR_ID(CS5536_OHCI_DEVICE_ID, CS5536_VENDOR_ID); | ||
81 | break; | ||
82 | case PCI_COMMAND: | ||
83 | _rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo); | ||
84 | if (hi & PCI_COMMAND_MASTER) | ||
85 | conf_data |= PCI_COMMAND_MASTER; | ||
86 | if (hi & PCI_COMMAND_MEMORY) | ||
87 | conf_data |= PCI_COMMAND_MEMORY; | ||
88 | break; | ||
89 | case PCI_STATUS: | ||
90 | conf_data |= PCI_STATUS_66MHZ; | ||
91 | conf_data |= PCI_STATUS_FAST_BACK; | ||
92 | _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo); | ||
93 | if (lo & SB_PARE_ERR_FLAG) | ||
94 | conf_data |= PCI_STATUS_PARITY; | ||
95 | conf_data |= PCI_STATUS_DEVSEL_MEDIUM; | ||
96 | break; | ||
97 | case PCI_CLASS_REVISION: | ||
98 | _rdmsr(USB_MSR_REG(USB_CAP), &hi, &lo); | ||
99 | conf_data = lo & 0x000000ff; | ||
100 | conf_data |= (CS5536_OHCI_CLASS_CODE << 8); | ||
101 | break; | ||
102 | case PCI_CACHE_LINE_SIZE: | ||
103 | conf_data = | ||
104 | CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE, | ||
105 | PCI_NORMAL_LATENCY_TIMER); | ||
106 | break; | ||
107 | case PCI_BAR0_REG: | ||
108 | _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo); | ||
109 | if (lo & SOFT_BAR_OHCI_FLAG) { | ||
110 | conf_data = CS5536_OHCI_RANGE | | ||
111 | PCI_BASE_ADDRESS_SPACE_MEMORY; | ||
112 | lo &= ~SOFT_BAR_OHCI_FLAG; | ||
113 | _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo); | ||
114 | } else { | ||
115 | _rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo); | ||
116 | conf_data = lo & 0xffffff00; | ||
117 | conf_data &= ~0x0000000f; /* 32bit mem */ | ||
118 | } | ||
119 | break; | ||
120 | case PCI_CARDBUS_CIS: | ||
121 | conf_data = PCI_CARDBUS_CIS_POINTER; | ||
122 | break; | ||
123 | case PCI_SUBSYSTEM_VENDOR_ID: | ||
124 | conf_data = | ||
125 | CFG_PCI_VENDOR_ID(CS5536_OHCI_SUB_ID, CS5536_SUB_VENDOR_ID); | ||
126 | break; | ||
127 | case PCI_ROM_ADDRESS: | ||
128 | conf_data = PCI_EXPANSION_ROM_BAR; | ||
129 | break; | ||
130 | case PCI_CAPABILITY_LIST: | ||
131 | conf_data = PCI_CAPLIST_USB_POINTER; | ||
132 | break; | ||
133 | case PCI_INTERRUPT_LINE: | ||
134 | conf_data = | ||
135 | CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_USB_INTR); | ||
136 | break; | ||
137 | case PCI_OHCI_INT_REG: | ||
138 | _rdmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), &hi, &lo); | ||
139 | if ((lo & 0x00000f00) == CS5536_USB_INTR) | ||
140 | conf_data = 1; | ||
141 | break; | ||
142 | default: | ||
143 | break; | ||
144 | } | ||
145 | |||
146 | return conf_data; | ||
147 | } | ||
diff --git a/arch/mips/loongson/common/cs5536/cs5536_pci.c b/arch/mips/loongson/common/cs5536/cs5536_pci.c new file mode 100644 index 000000000000..e23f3d7d2c1d --- /dev/null +++ b/arch/mips/loongson/common/cs5536/cs5536_pci.c | |||
@@ -0,0 +1,87 @@ | |||
1 | /* | ||
2 | * read/write operation to the PCI config space of CS5536 | ||
3 | * | ||
4 | * Copyright (C) 2007 Lemote, Inc. | ||
5 | * Author : jlliu, liujl@lemote.com | ||
6 | * | ||
7 | * Copyright (C) 2009 Lemote, Inc. | ||
8 | * Author: Wu Zhangjin, wuzj@lemote.com | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | * | ||
15 | * the Virtual Support Module(VSM) for virtulizing the PCI | ||
16 | * configure space are defined in cs5536_modulename.c respectively, | ||
17 | * | ||
18 | * after this virtulizing, user can access the PCI configure space | ||
19 | * directly as a normal multi-function PCI device which follows | ||
20 | * the PCI-2.2 spec. | ||
21 | */ | ||
22 | |||
23 | #include <linux/types.h> | ||
24 | #include <cs5536/cs5536_vsm.h> | ||
25 | |||
26 | enum { | ||
27 | CS5536_FUNC_START = -1, | ||
28 | CS5536_ISA_FUNC, | ||
29 | reserved_func, | ||
30 | CS5536_IDE_FUNC, | ||
31 | CS5536_ACC_FUNC, | ||
32 | CS5536_OHCI_FUNC, | ||
33 | CS5536_EHCI_FUNC, | ||
34 | CS5536_FUNC_END, | ||
35 | }; | ||
36 | |||
37 | static const cs5536_pci_vsm_write vsm_conf_write[] = { | ||
38 | [CS5536_ISA_FUNC] pci_isa_write_reg, | ||
39 | [reserved_func] NULL, | ||
40 | [CS5536_IDE_FUNC] pci_ide_write_reg, | ||
41 | [CS5536_ACC_FUNC] pci_acc_write_reg, | ||
42 | [CS5536_OHCI_FUNC] pci_ohci_write_reg, | ||
43 | [CS5536_EHCI_FUNC] pci_ehci_write_reg, | ||
44 | }; | ||
45 | |||
46 | static const cs5536_pci_vsm_read vsm_conf_read[] = { | ||
47 | [CS5536_ISA_FUNC] pci_isa_read_reg, | ||
48 | [reserved_func] NULL, | ||
49 | [CS5536_IDE_FUNC] pci_ide_read_reg, | ||
50 | [CS5536_ACC_FUNC] pci_acc_read_reg, | ||
51 | [CS5536_OHCI_FUNC] pci_ohci_read_reg, | ||
52 | [CS5536_EHCI_FUNC] pci_ehci_read_reg, | ||
53 | }; | ||
54 | |||
55 | /* | ||
56 | * write to PCI config space and transfer it to MSR write. | ||
57 | */ | ||
58 | void cs5536_pci_conf_write4(int function, int reg, u32 value) | ||
59 | { | ||
60 | if ((function <= CS5536_FUNC_START) || (function >= CS5536_FUNC_END)) | ||
61 | return; | ||
62 | if ((reg < 0) || (reg > 0x100) || ((reg & 0x03) != 0)) | ||
63 | return; | ||
64 | |||
65 | if (vsm_conf_write[function] != NULL) | ||
66 | vsm_conf_write[function](reg, value); | ||
67 | } | ||
68 | |||
69 | /* | ||
70 | * read PCI config space and transfer it to MSR access. | ||
71 | */ | ||
72 | u32 cs5536_pci_conf_read4(int function, int reg) | ||
73 | { | ||
74 | u32 data = 0; | ||
75 | |||
76 | if ((function <= CS5536_FUNC_START) || (function >= CS5536_FUNC_END)) | ||
77 | return 0; | ||
78 | if ((reg < 0) || ((reg & 0x03) != 0)) | ||
79 | return 0; | ||
80 | if (reg > 0x100) | ||
81 | return 0xffffffff; | ||
82 | |||
83 | if (vsm_conf_read[function] != NULL) | ||
84 | data = vsm_conf_read[function](reg); | ||
85 | |||
86 | return data; | ||
87 | } | ||
diff --git a/arch/mips/loongson/common/early_printk.c b/arch/mips/loongson/common/early_printk.c index bc73edc0cfd8..23e7a8f8897f 100644 --- a/arch/mips/loongson/common/early_printk.c +++ b/arch/mips/loongson/common/early_printk.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* early printk support | 1 | /* early printk support |
2 | * | 2 | * |
3 | * Copyright (c) 2009 Philippe Vachon <philippe@cowpig.ca> | 3 | * Copyright (c) 2009 Philippe Vachon <philippe@cowpig.ca> |
4 | * Copyright (C) 2009 Lemote Inc. & Insititute of Computing Technology | 4 | * Copyright (c) 2009 Lemote Inc. |
5 | * Author: Wu Zhangjin, wuzj@lemote.com | 5 | * Author: Wu Zhangjin, wuzj@lemote.com |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify it | 7 | * This program is free software; you can redistribute it and/or modify it |
@@ -12,26 +12,29 @@ | |||
12 | #include <linux/serial_reg.h> | 12 | #include <linux/serial_reg.h> |
13 | 13 | ||
14 | #include <loongson.h> | 14 | #include <loongson.h> |
15 | #include <machine.h> | ||
16 | 15 | ||
17 | #define PORT(base, offset) (u8 *)(base + offset) | 16 | #define PORT(base, offset) (u8 *)(base + offset) |
18 | 17 | ||
19 | static inline unsigned int serial_in(phys_addr_t base, int offset) | 18 | static inline unsigned int serial_in(unsigned char *base, int offset) |
20 | { | 19 | { |
21 | return readb(PORT(base, offset)); | 20 | return readb(PORT(base, offset)); |
22 | } | 21 | } |
23 | 22 | ||
24 | static inline void serial_out(phys_addr_t base, int offset, int value) | 23 | static inline void serial_out(unsigned char *base, int offset, int value) |
25 | { | 24 | { |
26 | writeb(value, PORT(base, offset)); | 25 | writeb(value, PORT(base, offset)); |
27 | } | 26 | } |
28 | 27 | ||
29 | void prom_putchar(char c) | 28 | void prom_putchar(char c) |
30 | { | 29 | { |
31 | phys_addr_t uart_base = | 30 | int timeout; |
32 | (phys_addr_t) ioremap_nocache(LOONGSON_UART_BASE, 8); | 31 | unsigned char *uart_base; |
33 | 32 | ||
34 | while ((serial_in(uart_base, UART_LSR) & UART_LSR_THRE) == 0) | 33 | uart_base = (unsigned char *)_loongson_uart_base; |
34 | timeout = 1024; | ||
35 | |||
36 | while (((serial_in(uart_base, UART_LSR) & UART_LSR_THRE) == 0) && | ||
37 | (timeout-- > 0)) | ||
35 | ; | 38 | ; |
36 | 39 | ||
37 | serial_out(uart_base, UART_TX, c); | 40 | serial_out(uart_base, UART_TX, c); |
diff --git a/arch/mips/loongson/common/env.c b/arch/mips/loongson/common/env.c index b9ef50385541..196d947d929a 100644 --- a/arch/mips/loongson/common/env.c +++ b/arch/mips/loongson/common/env.c | |||
@@ -17,11 +17,14 @@ | |||
17 | * Free Software Foundation; either version 2 of the License, or (at your | 17 | * Free Software Foundation; either version 2 of the License, or (at your |
18 | * option) any later version. | 18 | * option) any later version. |
19 | */ | 19 | */ |
20 | #include <linux/module.h> | ||
21 | |||
20 | #include <asm/bootinfo.h> | 22 | #include <asm/bootinfo.h> |
21 | 23 | ||
22 | #include <loongson.h> | 24 | #include <loongson.h> |
23 | 25 | ||
24 | unsigned long bus_clock, cpu_clock_freq; | 26 | unsigned long bus_clock, cpu_clock_freq; |
27 | EXPORT_SYMBOL(cpu_clock_freq); | ||
25 | unsigned long memsize, highmemsize; | 28 | unsigned long memsize, highmemsize; |
26 | 29 | ||
27 | /* pmon passes arguments in 32bit pointers */ | 30 | /* pmon passes arguments in 32bit pointers */ |
diff --git a/arch/mips/loongson/common/init.c b/arch/mips/loongson/common/init.c index 3abe927422a3..a2abd9355737 100644 --- a/arch/mips/loongson/common/init.c +++ b/arch/mips/loongson/common/init.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2009 Lemote Inc. & Insititute of Computing Technology | 2 | * Copyright (C) 2009 Lemote Inc. |
3 | * Author: Wu Zhangjin, wuzj@lemote.com | 3 | * Author: Wu Zhangjin, wuzj@lemote.com |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
@@ -10,19 +10,28 @@ | |||
10 | 10 | ||
11 | #include <linux/bootmem.h> | 11 | #include <linux/bootmem.h> |
12 | 12 | ||
13 | #include <asm/bootinfo.h> | ||
14 | |||
15 | #include <loongson.h> | 13 | #include <loongson.h> |
16 | 14 | ||
15 | /* Loongson CPU address windows config space base address */ | ||
16 | unsigned long __maybe_unused _loongson_addrwincfg_base; | ||
17 | |||
17 | void __init prom_init(void) | 18 | void __init prom_init(void) |
18 | { | 19 | { |
19 | /* init base address of io space */ | 20 | /* init base address of io space */ |
20 | set_io_port_base((unsigned long) | 21 | set_io_port_base((unsigned long) |
21 | ioremap(BONITO_PCIIO_BASE, BONITO_PCIIO_SIZE)); | 22 | ioremap(LOONGSON_PCIIO_BASE, LOONGSON_PCIIO_SIZE)); |
23 | |||
24 | #ifdef CONFIG_CPU_SUPPORTS_ADDRWINCFG | ||
25 | _loongson_addrwincfg_base = (unsigned long) | ||
26 | ioremap(LOONGSON_ADDRWINCFG_BASE, LOONGSON_ADDRWINCFG_SIZE); | ||
27 | #endif | ||
22 | 28 | ||
23 | prom_init_cmdline(); | 29 | prom_init_cmdline(); |
24 | prom_init_env(); | 30 | prom_init_env(); |
25 | prom_init_memory(); | 31 | prom_init_memory(); |
32 | |||
33 | /*init the uart base address */ | ||
34 | prom_init_uart_base(); | ||
26 | } | 35 | } |
27 | 36 | ||
28 | void __init prom_free_prom_memory(void) | 37 | void __init prom_free_prom_memory(void) |
diff --git a/arch/mips/loongson/common/irq.c b/arch/mips/loongson/common/irq.c index b32b4a3e5137..20e732831978 100644 --- a/arch/mips/loongson/common/irq.c +++ b/arch/mips/loongson/common/irq.c | |||
@@ -20,21 +20,21 @@ void bonito_irqdispatch(void) | |||
20 | int i; | 20 | int i; |
21 | 21 | ||
22 | /* workaround the IO dma problem: let cpu looping to allow DMA finish */ | 22 | /* workaround the IO dma problem: let cpu looping to allow DMA finish */ |
23 | int_status = BONITO_INTISR; | 23 | int_status = LOONGSON_INTISR; |
24 | if (int_status & (1 << 10)) { | 24 | if (int_status & (1 << 10)) { |
25 | while (int_status & (1 << 10)) { | 25 | while (int_status & (1 << 10)) { |
26 | udelay(1); | 26 | udelay(1); |
27 | int_status = BONITO_INTISR; | 27 | int_status = LOONGSON_INTISR; |
28 | } | 28 | } |
29 | } | 29 | } |
30 | 30 | ||
31 | /* Get pending sources, masked by current enables */ | 31 | /* Get pending sources, masked by current enables */ |
32 | int_status = BONITO_INTISR & BONITO_INTEN; | 32 | int_status = LOONGSON_INTISR & LOONGSON_INTEN; |
33 | 33 | ||
34 | if (int_status != 0) { | 34 | if (int_status != 0) { |
35 | i = __ffs(int_status); | 35 | i = __ffs(int_status); |
36 | int_status &= ~(1 << i); | 36 | int_status &= ~(1 << i); |
37 | do_IRQ(BONITO_IRQ_BASE + i); | 37 | do_IRQ(LOONGSON_IRQ_BASE + i); |
38 | } | 38 | } |
39 | } | 39 | } |
40 | 40 | ||
@@ -60,13 +60,13 @@ void __init arch_init_irq(void) | |||
60 | set_irq_trigger_mode(); | 60 | set_irq_trigger_mode(); |
61 | 61 | ||
62 | /* no steer */ | 62 | /* no steer */ |
63 | BONITO_INTSTEER = 0; | 63 | LOONGSON_INTSTEER = 0; |
64 | 64 | ||
65 | /* | 65 | /* |
66 | * Mask out all interrupt by writing "1" to all bit position in | 66 | * Mask out all interrupt by writing "1" to all bit position in |
67 | * the interrupt reset reg. | 67 | * the interrupt reset reg. |
68 | */ | 68 | */ |
69 | BONITO_INTENCLR = ~0; | 69 | LOONGSON_INTENCLR = ~0; |
70 | 70 | ||
71 | /* machine specific irq init */ | 71 | /* machine specific irq init */ |
72 | mach_init_irq(); | 72 | mach_init_irq(); |
diff --git a/arch/mips/loongson/common/machtype.c b/arch/mips/loongson/common/machtype.c index 7b348248de7d..0ed52b3f5314 100644 --- a/arch/mips/loongson/common/machtype.c +++ b/arch/mips/loongson/common/machtype.c | |||
@@ -15,6 +15,9 @@ | |||
15 | #include <loongson.h> | 15 | #include <loongson.h> |
16 | #include <machine.h> | 16 | #include <machine.h> |
17 | 17 | ||
18 | /* please ensure the length of the machtype string is less than 50 */ | ||
19 | #define MACHTYPE_LEN 50 | ||
20 | |||
18 | static const char *system_types[] = { | 21 | static const char *system_types[] = { |
19 | [MACH_LOONGSON_UNKNOWN] "unknown loongson machine", | 22 | [MACH_LOONGSON_UNKNOWN] "unknown loongson machine", |
20 | [MACH_LEMOTE_FL2E] "lemote-fuloong-2e-box", | 23 | [MACH_LEMOTE_FL2E] "lemote-fuloong-2e-box", |
@@ -22,29 +25,35 @@ static const char *system_types[] = { | |||
22 | [MACH_LEMOTE_ML2F7] "lemote-mengloong-2f-7inches", | 25 | [MACH_LEMOTE_ML2F7] "lemote-mengloong-2f-7inches", |
23 | [MACH_LEMOTE_YL2F89] "lemote-yeeloong-2f-8.9inches", | 26 | [MACH_LEMOTE_YL2F89] "lemote-yeeloong-2f-8.9inches", |
24 | [MACH_DEXXON_GDIUM2F10] "dexxon-gidum-2f-10inches", | 27 | [MACH_DEXXON_GDIUM2F10] "dexxon-gidum-2f-10inches", |
28 | [MACH_LEMOTE_NAS] "lemote-nas-2f", | ||
29 | [MACH_LEMOTE_LL2F] "lemote-lynloong-2f", | ||
25 | [MACH_LOONGSON_END] NULL, | 30 | [MACH_LOONGSON_END] NULL, |
26 | }; | 31 | }; |
27 | 32 | ||
28 | const char *get_system_type(void) | 33 | const char *get_system_type(void) |
29 | { | 34 | { |
30 | if (mips_machtype == MACH_UNKNOWN) | ||
31 | mips_machtype = LOONGSON_MACHTYPE; | ||
32 | |||
33 | return system_types[mips_machtype]; | 35 | return system_types[mips_machtype]; |
34 | } | 36 | } |
35 | 37 | ||
36 | static __init int machtype_setup(char *str) | 38 | void __init prom_init_machtype(void) |
37 | { | 39 | { |
40 | char *p, str[MACHTYPE_LEN]; | ||
38 | int machtype = MACH_LEMOTE_FL2E; | 41 | int machtype = MACH_LEMOTE_FL2E; |
39 | 42 | ||
40 | if (!str) | 43 | mips_machtype = LOONGSON_MACHTYPE; |
41 | return -EINVAL; | 44 | |
45 | p = strstr(arcs_cmdline, "machtype="); | ||
46 | if (!p) | ||
47 | return; | ||
48 | p += strlen("machtype="); | ||
49 | strncpy(str, p, MACHTYPE_LEN); | ||
50 | p = strstr(str, " "); | ||
51 | if (p) | ||
52 | *p = '\0'; | ||
42 | 53 | ||
43 | for (; system_types[machtype]; machtype++) | 54 | for (; system_types[machtype]; machtype++) |
44 | if (strstr(system_types[machtype], str)) { | 55 | if (strstr(system_types[machtype], str)) { |
45 | mips_machtype = machtype; | 56 | mips_machtype = machtype; |
46 | break; | 57 | break; |
47 | } | 58 | } |
48 | return 0; | ||
49 | } | 59 | } |
50 | __setup("machtype=", machtype_setup); | ||
diff --git a/arch/mips/loongson/common/mem.c b/arch/mips/loongson/common/mem.c index e94ef158f980..ceacd092b446 100644 --- a/arch/mips/loongson/common/mem.c +++ b/arch/mips/loongson/common/mem.c | |||
@@ -12,15 +12,40 @@ | |||
12 | 12 | ||
13 | #include <loongson.h> | 13 | #include <loongson.h> |
14 | #include <mem.h> | 14 | #include <mem.h> |
15 | #include <pci.h> | ||
15 | 16 | ||
16 | void __init prom_init_memory(void) | 17 | void __init prom_init_memory(void) |
17 | { | 18 | { |
18 | add_memory_region(0x0, (memsize << 20), BOOT_MEM_RAM); | 19 | add_memory_region(0x0, (memsize << 20), BOOT_MEM_RAM); |
20 | |||
21 | add_memory_region(memsize << 20, LOONGSON_PCI_MEM_START - (memsize << | ||
22 | 20), BOOT_MEM_RESERVED); | ||
23 | #ifdef CONFIG_CPU_SUPPORTS_ADDRWINCFG | ||
24 | { | ||
25 | int bit; | ||
26 | |||
27 | bit = fls(memsize + highmemsize); | ||
28 | if (bit != ffs(memsize + highmemsize)) | ||
29 | bit += 20; | ||
30 | else | ||
31 | bit = bit + 20 - 1; | ||
32 | |||
33 | /* set cpu window3 to map CPU to DDR: 2G -> 2G */ | ||
34 | LOONGSON_ADDRWIN_CPUTODDR(ADDRWIN_WIN3, 0x80000000ul, | ||
35 | 0x80000000ul, (1 << bit)); | ||
36 | mmiowb(); | ||
37 | } | ||
38 | #endif /* !CONFIG_CPU_SUPPORTS_ADDRWINCFG */ | ||
39 | |||
19 | #ifdef CONFIG_64BIT | 40 | #ifdef CONFIG_64BIT |
20 | if (highmemsize > 0) | 41 | if (highmemsize > 0) |
21 | add_memory_region(LOONGSON_HIGHMEM_START, | 42 | add_memory_region(LOONGSON_HIGHMEM_START, |
22 | highmemsize << 20, BOOT_MEM_RAM); | 43 | highmemsize << 20, BOOT_MEM_RAM); |
23 | #endif /* CONFIG_64BIT */ | 44 | |
45 | add_memory_region(LOONGSON_PCI_MEM_END + 1, LOONGSON_HIGHMEM_START - | ||
46 | LOONGSON_PCI_MEM_END - 1, BOOT_MEM_RESERVED); | ||
47 | |||
48 | #endif /* !CONFIG_64BIT */ | ||
24 | } | 49 | } |
25 | 50 | ||
26 | /* override of arch/mips/mm/cache.c: __uncached_access */ | 51 | /* override of arch/mips/mm/cache.c: __uncached_access */ |
@@ -33,3 +58,61 @@ int __uncached_access(struct file *file, unsigned long addr) | |||
33 | ((addr >= LOONGSON_MMIO_MEM_START) && | 58 | ((addr >= LOONGSON_MMIO_MEM_START) && |
34 | (addr < LOONGSON_MMIO_MEM_END)); | 59 | (addr < LOONGSON_MMIO_MEM_END)); |
35 | } | 60 | } |
61 | |||
62 | #ifdef CONFIG_CPU_SUPPORTS_UNCACHED_ACCELERATED | ||
63 | |||
64 | #include <linux/pci.h> | ||
65 | #include <linux/sched.h> | ||
66 | #include <asm/current.h> | ||
67 | |||
68 | static unsigned long uca_start, uca_end; | ||
69 | |||
70 | pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, | ||
71 | unsigned long size, pgprot_t vma_prot) | ||
72 | { | ||
73 | unsigned long offset = pfn << PAGE_SHIFT; | ||
74 | unsigned long end = offset + size; | ||
75 | |||
76 | if (__uncached_access(file, offset)) { | ||
77 | if (((uca_start && offset) >= uca_start) && | ||
78 | (end <= uca_end)) | ||
79 | return __pgprot((pgprot_val(vma_prot) & | ||
80 | ~_CACHE_MASK) | | ||
81 | _CACHE_UNCACHED_ACCELERATED); | ||
82 | else | ||
83 | return pgprot_noncached(vma_prot); | ||
84 | } | ||
85 | return vma_prot; | ||
86 | } | ||
87 | |||
88 | static int __init find_vga_mem_init(void) | ||
89 | { | ||
90 | struct pci_dev *dev = 0; | ||
91 | struct resource *r; | ||
92 | int idx; | ||
93 | |||
94 | if (uca_start) | ||
95 | return 0; | ||
96 | |||
97 | for_each_pci_dev(dev) { | ||
98 | if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) { | ||
99 | for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) { | ||
100 | r = &dev->resource[idx]; | ||
101 | if (!r->start && r->end) | ||
102 | continue; | ||
103 | if (r->flags & IORESOURCE_IO) | ||
104 | continue; | ||
105 | if (r->flags & IORESOURCE_MEM) { | ||
106 | uca_start = r->start; | ||
107 | uca_end = r->end; | ||
108 | return 0; | ||
109 | } | ||
110 | } | ||
111 | } | ||
112 | } | ||
113 | |||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | late_initcall(find_vga_mem_init); | ||
118 | #endif /* !CONFIG_CPU_SUPPORTS_UNCACHED_ACCELERATED */ | ||
diff --git a/arch/mips/loongson/common/pci.c b/arch/mips/loongson/common/pci.c index a3a4abfb6c9a..31d8c5ecd16c 100644 --- a/arch/mips/loongson/common/pci.c +++ b/arch/mips/loongson/common/pci.c | |||
@@ -27,7 +27,7 @@ static struct resource loongson_pci_io_resource = { | |||
27 | }; | 27 | }; |
28 | 28 | ||
29 | static struct pci_controller loongson_pci_controller = { | 29 | static struct pci_controller loongson_pci_controller = { |
30 | .pci_ops = &bonito64_pci_ops, | 30 | .pci_ops = &loongson_pci_ops, |
31 | .io_resource = &loongson_pci_io_resource, | 31 | .io_resource = &loongson_pci_io_resource, |
32 | .mem_resource = &loongson_pci_mem_resource, | 32 | .mem_resource = &loongson_pci_mem_resource, |
33 | .mem_offset = 0x00000000UL, | 33 | .mem_offset = 0x00000000UL, |
@@ -44,15 +44,15 @@ static void __init setup_pcimap(void) | |||
44 | * pcimap: PCI_MAP2 PCI_Mem_Lo2 PCI_Mem_Lo1 PCI_Mem_Lo0 | 44 | * pcimap: PCI_MAP2 PCI_Mem_Lo2 PCI_Mem_Lo1 PCI_Mem_Lo0 |
45 | * [<2G] [384M,448M] [320M,384M] [0M,64M] | 45 | * [<2G] [384M,448M] [320M,384M] [0M,64M] |
46 | */ | 46 | */ |
47 | BONITO_PCIMAP = BONITO_PCIMAP_PCIMAP_2 | | 47 | LOONGSON_PCIMAP = LOONGSON_PCIMAP_PCIMAP_2 | |
48 | BONITO_PCIMAP_WIN(2, BONITO_PCILO2_BASE) | | 48 | LOONGSON_PCIMAP_WIN(2, LOONGSON_PCILO2_BASE) | |
49 | BONITO_PCIMAP_WIN(1, BONITO_PCILO1_BASE) | | 49 | LOONGSON_PCIMAP_WIN(1, LOONGSON_PCILO1_BASE) | |
50 | BONITO_PCIMAP_WIN(0, 0); | 50 | LOONGSON_PCIMAP_WIN(0, 0); |
51 | 51 | ||
52 | /* | 52 | /* |
53 | * PCI-DMA to local mapping: [2G,2G+256M] -> [0M,256M] | 53 | * PCI-DMA to local mapping: [2G,2G+256M] -> [0M,256M] |
54 | */ | 54 | */ |
55 | BONITO_PCIBASE0 = 0x80000000ul; /* base: 2G -> mmap: 0M */ | 55 | LOONGSON_PCIBASE0 = 0x80000000ul; /* base: 2G -> mmap: 0M */ |
56 | /* size: 256M, burst transmission, pre-fetch enable, 64bit */ | 56 | /* size: 256M, burst transmission, pre-fetch enable, 64bit */ |
57 | LOONGSON_PCI_HIT0_SEL_L = 0xc000000cul; | 57 | LOONGSON_PCI_HIT0_SEL_L = 0xc000000cul; |
58 | LOONGSON_PCI_HIT0_SEL_H = 0xfffffffful; | 58 | LOONGSON_PCI_HIT0_SEL_H = 0xfffffffful; |
@@ -67,6 +67,14 @@ static void __init setup_pcimap(void) | |||
67 | /* can not change gnt to break pci transfer when device's gnt not | 67 | /* can not change gnt to break pci transfer when device's gnt not |
68 | deassert for some broken device */ | 68 | deassert for some broken device */ |
69 | LOONGSON_PXARB_CFG = 0x00fe0105ul; | 69 | LOONGSON_PXARB_CFG = 0x00fe0105ul; |
70 | |||
71 | #ifdef CONFIG_CPU_SUPPORTS_ADDRWINCFG | ||
72 | /* | ||
73 | * set cpu addr window2 to map CPU address space to PCI address space | ||
74 | */ | ||
75 | LOONGSON_ADDRWIN_CPUTOPCI(ADDRWIN_WIN2, LOONGSON_CPU_MEM_SRC, | ||
76 | LOONGSON_PCI_MEM_DST, MMAP_CPUTOPCI_SIZE); | ||
77 | #endif | ||
70 | } | 78 | } |
71 | 79 | ||
72 | static int __init pcibios_init(void) | 80 | static int __init pcibios_init(void) |
diff --git a/arch/mips/loongson/common/platform.c b/arch/mips/loongson/common/platform.c new file mode 100644 index 000000000000..be81777eb94d --- /dev/null +++ b/arch/mips/loongson/common/platform.c | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Lemote Inc. | ||
3 | * Author: Wu Zhangjin, wuzj@lemote.com | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
8 | * option) any later version. | ||
9 | */ | ||
10 | |||
11 | #include <linux/err.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | |||
14 | static struct platform_device loongson2_cpufreq_device = { | ||
15 | .name = "loongson2_cpufreq", | ||
16 | .id = -1, | ||
17 | }; | ||
18 | |||
19 | static int __init loongson2_cpufreq_init(void) | ||
20 | { | ||
21 | struct cpuinfo_mips *c = ¤t_cpu_data; | ||
22 | |||
23 | /* Only 2F revision and it's successors support CPUFreq */ | ||
24 | if ((c->processor_id & PRID_REV_MASK) >= PRID_REV_LOONGSON2F) | ||
25 | return platform_device_register(&loongson2_cpufreq_device); | ||
26 | |||
27 | return -ENODEV; | ||
28 | } | ||
29 | |||
30 | arch_initcall(loongson2_cpufreq_init); | ||
diff --git a/arch/mips/loongson/common/pm.c b/arch/mips/loongson/common/pm.c new file mode 100644 index 000000000000..b625fec8a4d5 --- /dev/null +++ b/arch/mips/loongson/common/pm.c | |||
@@ -0,0 +1,161 @@ | |||
1 | /* | ||
2 | * loongson-specific suspend support | ||
3 | * | ||
4 | * Copyright (C) 2009 Lemote Inc. | ||
5 | * Author: Wu Zhangjin <wuzj@lemote.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | */ | ||
12 | #include <linux/suspend.h> | ||
13 | #include <linux/interrupt.h> | ||
14 | #include <linux/pm.h> | ||
15 | |||
16 | #include <asm/i8259.h> | ||
17 | #include <asm/mipsregs.h> | ||
18 | |||
19 | #include <loongson.h> | ||
20 | |||
21 | static unsigned int __maybe_unused cached_master_mask; /* i8259A */ | ||
22 | static unsigned int __maybe_unused cached_slave_mask; | ||
23 | static unsigned int __maybe_unused cached_bonito_irq_mask; /* bonito */ | ||
24 | |||
25 | void arch_suspend_disable_irqs(void) | ||
26 | { | ||
27 | /* disable all mips events */ | ||
28 | local_irq_disable(); | ||
29 | |||
30 | #ifdef CONFIG_I8259 | ||
31 | /* disable all events of i8259A */ | ||
32 | cached_slave_mask = inb(PIC_SLAVE_IMR); | ||
33 | cached_master_mask = inb(PIC_MASTER_IMR); | ||
34 | |||
35 | outb(0xff, PIC_SLAVE_IMR); | ||
36 | inb(PIC_SLAVE_IMR); | ||
37 | outb(0xff, PIC_MASTER_IMR); | ||
38 | inb(PIC_MASTER_IMR); | ||
39 | #endif | ||
40 | /* disable all events of bonito */ | ||
41 | cached_bonito_irq_mask = LOONGSON_INTEN; | ||
42 | LOONGSON_INTENCLR = 0xffff; | ||
43 | (void)LOONGSON_INTENCLR; | ||
44 | } | ||
45 | |||
46 | void arch_suspend_enable_irqs(void) | ||
47 | { | ||
48 | /* enable all mips events */ | ||
49 | local_irq_enable(); | ||
50 | #ifdef CONFIG_I8259 | ||
51 | /* only enable the cached events of i8259A */ | ||
52 | outb(cached_slave_mask, PIC_SLAVE_IMR); | ||
53 | outb(cached_master_mask, PIC_MASTER_IMR); | ||
54 | #endif | ||
55 | /* enable all cached events of bonito */ | ||
56 | LOONGSON_INTENSET = cached_bonito_irq_mask; | ||
57 | (void)LOONGSON_INTENSET; | ||
58 | } | ||
59 | |||
60 | /* | ||
61 | * Setup the board-specific events for waking up loongson from wait mode | ||
62 | */ | ||
63 | void __weak setup_wakeup_events(void) | ||
64 | { | ||
65 | } | ||
66 | |||
67 | /* | ||
68 | * Check wakeup events | ||
69 | */ | ||
70 | int __weak wakeup_loongson(void) | ||
71 | { | ||
72 | return 1; | ||
73 | } | ||
74 | |||
75 | /* | ||
76 | * If the events are really what we want to wakeup the CPU, wake it up | ||
77 | * otherwise put the CPU asleep again. | ||
78 | */ | ||
79 | static void wait_for_wakeup_events(void) | ||
80 | { | ||
81 | while (!wakeup_loongson()) | ||
82 | LOONGSON_CHIPCFG0 &= ~0x7; | ||
83 | } | ||
84 | |||
85 | /* | ||
86 | * Stop all perf counters | ||
87 | * | ||
88 | * $24 is the control register of Loongson perf counter | ||
89 | */ | ||
90 | static inline void stop_perf_counters(void) | ||
91 | { | ||
92 | __write_64bit_c0_register($24, 0, 0); | ||
93 | } | ||
94 | |||
95 | |||
96 | static void loongson_suspend_enter(void) | ||
97 | { | ||
98 | static unsigned int cached_cpu_freq; | ||
99 | |||
100 | /* setup wakeup events via enabling the IRQs */ | ||
101 | setup_wakeup_events(); | ||
102 | |||
103 | stop_perf_counters(); | ||
104 | |||
105 | cached_cpu_freq = LOONGSON_CHIPCFG0; | ||
106 | |||
107 | /* Put CPU into wait mode */ | ||
108 | LOONGSON_CHIPCFG0 &= ~0x7; | ||
109 | |||
110 | /* wait for the given events to wakeup cpu from wait mode */ | ||
111 | wait_for_wakeup_events(); | ||
112 | |||
113 | LOONGSON_CHIPCFG0 = cached_cpu_freq; | ||
114 | mmiowb(); | ||
115 | } | ||
116 | |||
117 | void __weak mach_suspend(void) | ||
118 | { | ||
119 | } | ||
120 | |||
121 | void __weak mach_resume(void) | ||
122 | { | ||
123 | } | ||
124 | |||
125 | static int loongson_pm_enter(suspend_state_t state) | ||
126 | { | ||
127 | mach_suspend(); | ||
128 | |||
129 | /* processor specific suspend */ | ||
130 | loongson_suspend_enter(); | ||
131 | |||
132 | mach_resume(); | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static int loongson_pm_valid_state(suspend_state_t state) | ||
138 | { | ||
139 | switch (state) { | ||
140 | case PM_SUSPEND_ON: | ||
141 | case PM_SUSPEND_STANDBY: | ||
142 | case PM_SUSPEND_MEM: | ||
143 | return 1; | ||
144 | |||
145 | default: | ||
146 | return 0; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | static struct platform_suspend_ops loongson_pm_ops = { | ||
151 | .valid = loongson_pm_valid_state, | ||
152 | .enter = loongson_pm_enter, | ||
153 | }; | ||
154 | |||
155 | static int __init loongson_pm_init(void) | ||
156 | { | ||
157 | suspend_set_ops(&loongson_pm_ops); | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | arch_initcall(loongson_pm_init); | ||
diff --git a/arch/mips/loongson/common/reset.c b/arch/mips/loongson/common/reset.c index 97e918251edd..d57f1719da95 100644 --- a/arch/mips/loongson/common/reset.c +++ b/arch/mips/loongson/common/reset.c | |||
@@ -22,7 +22,7 @@ static void loongson_restart(char *command) | |||
22 | mach_prepare_reboot(); | 22 | mach_prepare_reboot(); |
23 | 23 | ||
24 | /* reboot via jumping to boot base address */ | 24 | /* reboot via jumping to boot base address */ |
25 | ((void (*)(void))ioremap_nocache(BONITO_BOOT_BASE, 4)) (); | 25 | ((void (*)(void))ioremap_nocache(LOONGSON_BOOT_BASE, 4)) (); |
26 | } | 26 | } |
27 | 27 | ||
28 | static void loongson_halt(void) | 28 | static void loongson_halt(void) |
diff --git a/arch/mips/loongson/common/serial.c b/arch/mips/loongson/common/serial.c new file mode 100644 index 000000000000..23b66a5f88cb --- /dev/null +++ b/arch/mips/loongson/common/serial.c | |||
@@ -0,0 +1,76 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org) | ||
7 | * | ||
8 | * Copyright (C) 2009 Lemote, Inc. | ||
9 | * Author: Yan hua (yanhua@lemote.com) | ||
10 | * Author: Wu Zhangjin (wuzj@lemote.com) | ||
11 | */ | ||
12 | |||
13 | #include <linux/io.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/serial_8250.h> | ||
16 | |||
17 | #include <asm/bootinfo.h> | ||
18 | |||
19 | #include <loongson.h> | ||
20 | #include <machine.h> | ||
21 | |||
22 | #define PORT(int) \ | ||
23 | { \ | ||
24 | .irq = int, \ | ||
25 | .uartclk = 1843200, \ | ||
26 | .iotype = UPIO_PORT, \ | ||
27 | .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, \ | ||
28 | .regshift = 0, \ | ||
29 | } | ||
30 | |||
31 | #define PORT_M(int) \ | ||
32 | { \ | ||
33 | .irq = MIPS_CPU_IRQ_BASE + (int), \ | ||
34 | .uartclk = 3686400, \ | ||
35 | .iotype = UPIO_MEM, \ | ||
36 | .membase = (void __iomem *)NULL, \ | ||
37 | .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, \ | ||
38 | .regshift = 0, \ | ||
39 | } | ||
40 | |||
41 | static struct plat_serial8250_port uart8250_data[][2] = { | ||
42 | [MACH_LOONGSON_UNKNOWN] {}, | ||
43 | [MACH_LEMOTE_FL2E] {PORT(4), {} }, | ||
44 | [MACH_LEMOTE_FL2F] {PORT(3), {} }, | ||
45 | [MACH_LEMOTE_ML2F7] {PORT_M(3), {} }, | ||
46 | [MACH_LEMOTE_YL2F89] {PORT_M(3), {} }, | ||
47 | [MACH_DEXXON_GDIUM2F10] {PORT_M(3), {} }, | ||
48 | [MACH_LEMOTE_NAS] {PORT_M(3), {} }, | ||
49 | [MACH_LEMOTE_LL2F] {PORT(3), {} }, | ||
50 | [MACH_LOONGSON_END] {}, | ||
51 | }; | ||
52 | |||
53 | static struct platform_device uart8250_device = { | ||
54 | .name = "serial8250", | ||
55 | .id = PLAT8250_DEV_PLATFORM, | ||
56 | }; | ||
57 | |||
58 | static int __init serial_init(void) | ||
59 | { | ||
60 | unsigned char iotype; | ||
61 | |||
62 | iotype = uart8250_data[mips_machtype][0].iotype; | ||
63 | |||
64 | if (UPIO_MEM == iotype) | ||
65 | uart8250_data[mips_machtype][0].membase = | ||
66 | (void __iomem *)_loongson_uart_base; | ||
67 | else if (UPIO_PORT == iotype) | ||
68 | uart8250_data[mips_machtype][0].iobase = | ||
69 | loongson_uart_base - LOONGSON_PCIIO_BASE; | ||
70 | |||
71 | uart8250_device.dev.platform_data = uart8250_data[mips_machtype]; | ||
72 | |||
73 | return platform_device_register(&uart8250_device); | ||
74 | } | ||
75 | |||
76 | device_initcall(serial_init); | ||
diff --git a/arch/mips/loongson/common/time.c b/arch/mips/loongson/common/time.c index 6e08c8270abe..35f0b66a94f5 100644 --- a/arch/mips/loongson/common/time.c +++ b/arch/mips/loongson/common/time.c | |||
@@ -14,11 +14,14 @@ | |||
14 | #include <asm/time.h> | 14 | #include <asm/time.h> |
15 | 15 | ||
16 | #include <loongson.h> | 16 | #include <loongson.h> |
17 | #include <cs5536/cs5536_mfgpt.h> | ||
17 | 18 | ||
18 | void __init plat_time_init(void) | 19 | void __init plat_time_init(void) |
19 | { | 20 | { |
20 | /* setup mips r4k timer */ | 21 | /* setup mips r4k timer */ |
21 | mips_hpt_frequency = cpu_clock_freq / 2; | 22 | mips_hpt_frequency = cpu_clock_freq / 2; |
23 | |||
24 | setup_mfgpt0_timer(); | ||
22 | } | 25 | } |
23 | 26 | ||
24 | void read_persistent_clock(struct timespec *ts) | 27 | void read_persistent_clock(struct timespec *ts) |
diff --git a/arch/mips/loongson/common/uart_base.c b/arch/mips/loongson/common/uart_base.c new file mode 100644 index 000000000000..78ff66ae749e --- /dev/null +++ b/arch/mips/loongson/common/uart_base.c | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Lemote Inc. | ||
3 | * Author: Wu Zhangjin, wuzj@lemote.com | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
8 | * option) any later version. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <asm/bootinfo.h> | ||
13 | |||
14 | #include <loongson.h> | ||
15 | |||
16 | /* ioremapped */ | ||
17 | unsigned long _loongson_uart_base; | ||
18 | EXPORT_SYMBOL(_loongson_uart_base); | ||
19 | /* raw */ | ||
20 | unsigned long loongson_uart_base; | ||
21 | EXPORT_SYMBOL(loongson_uart_base); | ||
22 | |||
23 | void prom_init_loongson_uart_base(void) | ||
24 | { | ||
25 | switch (mips_machtype) { | ||
26 | case MACH_LEMOTE_FL2E: | ||
27 | loongson_uart_base = LOONGSON_PCIIO_BASE + 0x3f8; | ||
28 | break; | ||
29 | case MACH_LEMOTE_FL2F: | ||
30 | case MACH_LEMOTE_LL2F: | ||
31 | loongson_uart_base = LOONGSON_PCIIO_BASE + 0x2f8; | ||
32 | break; | ||
33 | case MACH_LEMOTE_ML2F7: | ||
34 | case MACH_LEMOTE_YL2F89: | ||
35 | case MACH_DEXXON_GDIUM2F10: | ||
36 | case MACH_LEMOTE_NAS: | ||
37 | default: | ||
38 | /* The CPU provided serial port */ | ||
39 | loongson_uart_base = LOONGSON_LIO1_BASE + 0x3f8; | ||
40 | break; | ||
41 | } | ||
42 | |||
43 | _loongson_uart_base = | ||
44 | (unsigned long)ioremap_nocache(loongson_uart_base, 8); | ||
45 | } | ||
diff --git a/arch/mips/loongson/fuloong-2e/irq.c b/arch/mips/loongson/fuloong-2e/irq.c index 7888cf69424a..320e9379bdd7 100644 --- a/arch/mips/loongson/fuloong-2e/irq.c +++ b/arch/mips/loongson/fuloong-2e/irq.c | |||
@@ -47,8 +47,8 @@ static struct irqaction cascade_irqaction = { | |||
47 | void __init set_irq_trigger_mode(void) | 47 | void __init set_irq_trigger_mode(void) |
48 | { | 48 | { |
49 | /* most bonito irq should be level triggered */ | 49 | /* most bonito irq should be level triggered */ |
50 | BONITO_INTEDGE = BONITO_ICU_SYSTEMERR | BONITO_ICU_MASTERERR | | 50 | LOONGSON_INTEDGE = LOONGSON_ICU_SYSTEMERR | LOONGSON_ICU_MASTERERR | |
51 | BONITO_ICU_RETRYERR | BONITO_ICU_MBOXES; | 51 | LOONGSON_ICU_RETRYERR | LOONGSON_ICU_MBOXES; |
52 | } | 52 | } |
53 | 53 | ||
54 | void __init mach_init_irq(void) | 54 | void __init mach_init_irq(void) |
diff --git a/arch/mips/loongson/fuloong-2e/reset.c b/arch/mips/loongson/fuloong-2e/reset.c index 677fe186db95..fc16c677d476 100644 --- a/arch/mips/loongson/fuloong-2e/reset.c +++ b/arch/mips/loongson/fuloong-2e/reset.c | |||
@@ -14,8 +14,8 @@ | |||
14 | 14 | ||
15 | void mach_prepare_reboot(void) | 15 | void mach_prepare_reboot(void) |
16 | { | 16 | { |
17 | BONITO_BONGENCFG &= ~(1 << 2); | 17 | LOONGSON_GENCFG &= ~(1 << 2); |
18 | BONITO_BONGENCFG |= (1 << 2); | 18 | LOONGSON_GENCFG |= (1 << 2); |
19 | } | 19 | } |
20 | 20 | ||
21 | void mach_prepare_shutdown(void) | 21 | void mach_prepare_shutdown(void) |
diff --git a/arch/mips/loongson/lemote-2f/Makefile b/arch/mips/loongson/lemote-2f/Makefile new file mode 100644 index 000000000000..4d84b27dc41b --- /dev/null +++ b/arch/mips/loongson/lemote-2f/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # | ||
2 | # Makefile for lemote loongson2f family machines | ||
3 | # | ||
4 | |||
5 | obj-y += irq.o reset.o ec_kb3310b.o | ||
6 | |||
7 | # | ||
8 | # Suspend Support | ||
9 | # | ||
10 | |||
11 | obj-$(CONFIG_LOONGSON_SUSPEND) += pm.o | ||
diff --git a/arch/mips/loongson/lemote-2f/ec_kb3310b.c b/arch/mips/loongson/lemote-2f/ec_kb3310b.c new file mode 100644 index 000000000000..4d84111a2cd4 --- /dev/null +++ b/arch/mips/loongson/lemote-2f/ec_kb3310b.c | |||
@@ -0,0 +1,130 @@ | |||
1 | /* | ||
2 | * Basic KB3310B Embedded Controller support for the YeeLoong 2F netbook | ||
3 | * | ||
4 | * Copyright (C) 2008 Lemote Inc. | ||
5 | * Author: liujl <liujl@lemote.com>, 2008-04-20 | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/spinlock.h> | ||
15 | #include <linux/delay.h> | ||
16 | |||
17 | #include "ec_kb3310b.h" | ||
18 | |||
19 | static DEFINE_SPINLOCK(index_access_lock); | ||
20 | static DEFINE_SPINLOCK(port_access_lock); | ||
21 | |||
22 | unsigned char ec_read(unsigned short addr) | ||
23 | { | ||
24 | unsigned char value; | ||
25 | unsigned long flags; | ||
26 | |||
27 | spin_lock_irqsave(&index_access_lock, flags); | ||
28 | outb((addr & 0xff00) >> 8, EC_IO_PORT_HIGH); | ||
29 | outb((addr & 0x00ff), EC_IO_PORT_LOW); | ||
30 | value = inb(EC_IO_PORT_DATA); | ||
31 | spin_unlock_irqrestore(&index_access_lock, flags); | ||
32 | |||
33 | return value; | ||
34 | } | ||
35 | EXPORT_SYMBOL_GPL(ec_read); | ||
36 | |||
37 | void ec_write(unsigned short addr, unsigned char val) | ||
38 | { | ||
39 | unsigned long flags; | ||
40 | |||
41 | spin_lock_irqsave(&index_access_lock, flags); | ||
42 | outb((addr & 0xff00) >> 8, EC_IO_PORT_HIGH); | ||
43 | outb((addr & 0x00ff), EC_IO_PORT_LOW); | ||
44 | outb(val, EC_IO_PORT_DATA); | ||
45 | /* flush the write action */ | ||
46 | inb(EC_IO_PORT_DATA); | ||
47 | spin_unlock_irqrestore(&index_access_lock, flags); | ||
48 | |||
49 | return; | ||
50 | } | ||
51 | EXPORT_SYMBOL_GPL(ec_write); | ||
52 | |||
53 | /* | ||
54 | * This function is used for EC command writes and corresponding status queries. | ||
55 | */ | ||
56 | int ec_query_seq(unsigned char cmd) | ||
57 | { | ||
58 | int timeout; | ||
59 | unsigned char status; | ||
60 | unsigned long flags; | ||
61 | int ret = 0; | ||
62 | |||
63 | spin_lock_irqsave(&port_access_lock, flags); | ||
64 | |||
65 | /* make chip goto reset mode */ | ||
66 | udelay(EC_REG_DELAY); | ||
67 | outb(cmd, EC_CMD_PORT); | ||
68 | udelay(EC_REG_DELAY); | ||
69 | |||
70 | /* check if the command is received by ec */ | ||
71 | timeout = EC_CMD_TIMEOUT; | ||
72 | status = inb(EC_STS_PORT); | ||
73 | while (timeout-- && (status & (1 << 1))) { | ||
74 | status = inb(EC_STS_PORT); | ||
75 | udelay(EC_REG_DELAY); | ||
76 | } | ||
77 | |||
78 | if (timeout <= 0) { | ||
79 | printk(KERN_ERR "%s: deadable error : timeout...\n", __func__); | ||
80 | ret = -EINVAL; | ||
81 | } else | ||
82 | printk(KERN_INFO | ||
83 | "(%x/%d)ec issued command %d status : 0x%x\n", | ||
84 | timeout, EC_CMD_TIMEOUT - timeout, cmd, status); | ||
85 | |||
86 | spin_unlock_irqrestore(&port_access_lock, flags); | ||
87 | |||
88 | return ret; | ||
89 | } | ||
90 | EXPORT_SYMBOL_GPL(ec_query_seq); | ||
91 | |||
92 | /* | ||
93 | * Send query command to EC to get the proper event number | ||
94 | */ | ||
95 | int ec_query_event_num(void) | ||
96 | { | ||
97 | return ec_query_seq(CMD_GET_EVENT_NUM); | ||
98 | } | ||
99 | EXPORT_SYMBOL(ec_query_event_num); | ||
100 | |||
101 | /* | ||
102 | * Get event number from EC | ||
103 | * | ||
104 | * NOTE: This routine must follow the query_event_num function in the | ||
105 | * interrupt. | ||
106 | */ | ||
107 | int ec_get_event_num(void) | ||
108 | { | ||
109 | int timeout = 100; | ||
110 | unsigned char value; | ||
111 | unsigned char status; | ||
112 | |||
113 | udelay(EC_REG_DELAY); | ||
114 | status = inb(EC_STS_PORT); | ||
115 | udelay(EC_REG_DELAY); | ||
116 | while (timeout-- && !(status & (1 << 0))) { | ||
117 | status = inb(EC_STS_PORT); | ||
118 | udelay(EC_REG_DELAY); | ||
119 | } | ||
120 | if (timeout <= 0) { | ||
121 | pr_info("%s: get event number timeout.\n", __func__); | ||
122 | |||
123 | return -EINVAL; | ||
124 | } | ||
125 | value = inb(EC_DAT_PORT); | ||
126 | udelay(EC_REG_DELAY); | ||
127 | |||
128 | return value; | ||
129 | } | ||
130 | EXPORT_SYMBOL(ec_get_event_num); | ||
diff --git a/arch/mips/loongson/lemote-2f/ec_kb3310b.h b/arch/mips/loongson/lemote-2f/ec_kb3310b.h new file mode 100644 index 000000000000..1595a21b315b --- /dev/null +++ b/arch/mips/loongson/lemote-2f/ec_kb3310b.h | |||
@@ -0,0 +1,188 @@ | |||
1 | /* | ||
2 | * KB3310B Embedded Controller | ||
3 | * | ||
4 | * Copyright (C) 2008 Lemote Inc. | ||
5 | * Author: liujl <liujl@lemote.com>, 2008-03-14 | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #ifndef _EC_KB3310B_H | ||
14 | #define _EC_KB3310B_H | ||
15 | |||
16 | extern unsigned char ec_read(unsigned short addr); | ||
17 | extern void ec_write(unsigned short addr, unsigned char val); | ||
18 | extern int ec_query_seq(unsigned char cmd); | ||
19 | extern int ec_query_event_num(void); | ||
20 | extern int ec_get_event_num(void); | ||
21 | |||
22 | typedef int (*sci_handler) (int status); | ||
23 | extern sci_handler yeeloong_report_lid_status; | ||
24 | |||
25 | #define SCI_IRQ_NUM 0x0A | ||
26 | |||
27 | /* | ||
28 | * The following registers are determined by the EC index configuration. | ||
29 | * 1, fill the PORT_HIGH as EC register high part. | ||
30 | * 2, fill the PORT_LOW as EC register low part. | ||
31 | * 3, fill the PORT_DATA as EC register write data or get the data from it. | ||
32 | */ | ||
33 | #define EC_IO_PORT_HIGH 0x0381 | ||
34 | #define EC_IO_PORT_LOW 0x0382 | ||
35 | #define EC_IO_PORT_DATA 0x0383 | ||
36 | |||
37 | /* | ||
38 | * EC delay time is 500us for register and status access | ||
39 | */ | ||
40 | #define EC_REG_DELAY 500 /* unit : us */ | ||
41 | #define EC_CMD_TIMEOUT 0x1000 | ||
42 | |||
43 | /* | ||
44 | * EC access port for SCI communication | ||
45 | */ | ||
46 | #define EC_CMD_PORT 0x66 | ||
47 | #define EC_STS_PORT 0x66 | ||
48 | #define EC_DAT_PORT 0x62 | ||
49 | #define CMD_INIT_IDLE_MODE 0xdd | ||
50 | #define CMD_EXIT_IDLE_MODE 0xdf | ||
51 | #define CMD_INIT_RESET_MODE 0xd8 | ||
52 | #define CMD_REBOOT_SYSTEM 0x8c | ||
53 | #define CMD_GET_EVENT_NUM 0x84 | ||
54 | #define CMD_PROGRAM_PIECE 0xda | ||
55 | |||
56 | /* temperature & fan registers */ | ||
57 | #define REG_TEMPERATURE_VALUE 0xF458 | ||
58 | #define REG_FAN_AUTO_MAN_SWITCH 0xF459 | ||
59 | #define BIT_FAN_AUTO 0 | ||
60 | #define BIT_FAN_MANUAL 1 | ||
61 | #define REG_FAN_CONTROL 0xF4D2 | ||
62 | #define BIT_FAN_CONTROL_ON (1 << 0) | ||
63 | #define BIT_FAN_CONTROL_OFF (0 << 0) | ||
64 | #define REG_FAN_STATUS 0xF4DA | ||
65 | #define BIT_FAN_STATUS_ON (1 << 0) | ||
66 | #define BIT_FAN_STATUS_OFF (0 << 0) | ||
67 | #define REG_FAN_SPEED_HIGH 0xFE22 | ||
68 | #define REG_FAN_SPEED_LOW 0xFE23 | ||
69 | #define REG_FAN_SPEED_LEVEL 0xF4CC | ||
70 | /* fan speed divider */ | ||
71 | #define FAN_SPEED_DIVIDER 480000 /* (60*1000*1000/62.5/2)*/ | ||
72 | |||
73 | /* battery registers */ | ||
74 | #define REG_BAT_DESIGN_CAP_HIGH 0xF77D | ||
75 | #define REG_BAT_DESIGN_CAP_LOW 0xF77E | ||
76 | #define REG_BAT_FULLCHG_CAP_HIGH 0xF780 | ||
77 | #define REG_BAT_FULLCHG_CAP_LOW 0xF781 | ||
78 | #define REG_BAT_DESIGN_VOL_HIGH 0xF782 | ||
79 | #define REG_BAT_DESIGN_VOL_LOW 0xF783 | ||
80 | #define REG_BAT_CURRENT_HIGH 0xF784 | ||
81 | #define REG_BAT_CURRENT_LOW 0xF785 | ||
82 | #define REG_BAT_VOLTAGE_HIGH 0xF786 | ||
83 | #define REG_BAT_VOLTAGE_LOW 0xF787 | ||
84 | #define REG_BAT_TEMPERATURE_HIGH 0xF788 | ||
85 | #define REG_BAT_TEMPERATURE_LOW 0xF789 | ||
86 | #define REG_BAT_RELATIVE_CAP_HIGH 0xF492 | ||
87 | #define REG_BAT_RELATIVE_CAP_LOW 0xF493 | ||
88 | #define REG_BAT_VENDOR 0xF4C4 | ||
89 | #define FLAG_BAT_VENDOR_SANYO 0x01 | ||
90 | #define FLAG_BAT_VENDOR_SIMPLO 0x02 | ||
91 | #define REG_BAT_CELL_COUNT 0xF4C6 | ||
92 | #define FLAG_BAT_CELL_3S1P 0x03 | ||
93 | #define FLAG_BAT_CELL_3S2P 0x06 | ||
94 | #define REG_BAT_CHARGE 0xF4A2 | ||
95 | #define FLAG_BAT_CHARGE_DISCHARGE 0x01 | ||
96 | #define FLAG_BAT_CHARGE_CHARGE 0x02 | ||
97 | #define FLAG_BAT_CHARGE_ACPOWER 0x00 | ||
98 | #define REG_BAT_STATUS 0xF4B0 | ||
99 | #define BIT_BAT_STATUS_LOW (1 << 5) | ||
100 | #define BIT_BAT_STATUS_DESTROY (1 << 2) | ||
101 | #define BIT_BAT_STATUS_FULL (1 << 1) | ||
102 | #define BIT_BAT_STATUS_IN (1 << 0) | ||
103 | #define REG_BAT_CHARGE_STATUS 0xF4B1 | ||
104 | #define BIT_BAT_CHARGE_STATUS_OVERTEMP (1 << 2) | ||
105 | #define BIT_BAT_CHARGE_STATUS_PRECHG (1 << 1) | ||
106 | #define REG_BAT_STATE 0xF482 | ||
107 | #define BIT_BAT_STATE_CHARGING (1 << 1) | ||
108 | #define BIT_BAT_STATE_DISCHARGING (1 << 0) | ||
109 | #define REG_BAT_POWER 0xF440 | ||
110 | #define BIT_BAT_POWER_S3 (1 << 2) | ||
111 | #define BIT_BAT_POWER_ON (1 << 1) | ||
112 | #define BIT_BAT_POWER_ACIN (1 << 0) | ||
113 | |||
114 | /* other registers */ | ||
115 | /* Audio: rd/wr */ | ||
116 | #define REG_AUDIO_VOLUME 0xF46C | ||
117 | #define REG_AUDIO_MUTE 0xF4E7 | ||
118 | #define REG_AUDIO_BEEP 0xF4D0 | ||
119 | /* USB port power or not: rd/wr */ | ||
120 | #define REG_USB0_FLAG 0xF461 | ||
121 | #define REG_USB1_FLAG 0xF462 | ||
122 | #define REG_USB2_FLAG 0xF463 | ||
123 | #define BIT_USB_FLAG_ON 1 | ||
124 | #define BIT_USB_FLAG_OFF 0 | ||
125 | /* LID */ | ||
126 | #define REG_LID_DETECT 0xF4BD | ||
127 | #define BIT_LID_DETECT_ON 1 | ||
128 | #define BIT_LID_DETECT_OFF 0 | ||
129 | /* CRT */ | ||
130 | #define REG_CRT_DETECT 0xF4AD | ||
131 | #define BIT_CRT_DETECT_PLUG 1 | ||
132 | #define BIT_CRT_DETECT_UNPLUG 0 | ||
133 | /* LCD backlight brightness adjust: 9 levels */ | ||
134 | #define REG_DISPLAY_BRIGHTNESS 0xF4F5 | ||
135 | /* Black screen Status */ | ||
136 | #define BIT_DISPLAY_LCD_ON 1 | ||
137 | #define BIT_DISPLAY_LCD_OFF 0 | ||
138 | /* LCD backlight control: off/restore */ | ||
139 | #define REG_BACKLIGHT_CTRL 0xF7BD | ||
140 | #define BIT_BACKLIGHT_ON 1 | ||
141 | #define BIT_BACKLIGHT_OFF 0 | ||
142 | /* Reset the machine auto-clear: rd/wr */ | ||
143 | #define REG_RESET 0xF4EC | ||
144 | #define BIT_RESET_ON 1 | ||
145 | /* Light the led: rd/wr */ | ||
146 | #define REG_LED 0xF4C8 | ||
147 | #define BIT_LED_RED_POWER (1 << 0) | ||
148 | #define BIT_LED_ORANGE_POWER (1 << 1) | ||
149 | #define BIT_LED_GREEN_CHARGE (1 << 2) | ||
150 | #define BIT_LED_RED_CHARGE (1 << 3) | ||
151 | #define BIT_LED_NUMLOCK (1 << 4) | ||
152 | /* Test led mode, all led on/off */ | ||
153 | #define REG_LED_TEST 0xF4C2 | ||
154 | #define BIT_LED_TEST_IN 1 | ||
155 | #define BIT_LED_TEST_OUT 0 | ||
156 | /* Camera on/off */ | ||
157 | #define REG_CAMERA_STATUS 0xF46A | ||
158 | #define BIT_CAMERA_STATUS_ON 1 | ||
159 | #define BIT_CAMERA_STATUS_OFF 0 | ||
160 | #define REG_CAMERA_CONTROL 0xF7B7 | ||
161 | #define BIT_CAMERA_CONTROL_OFF 0 | ||
162 | #define BIT_CAMERA_CONTROL_ON 1 | ||
163 | /* Wlan Status */ | ||
164 | #define REG_WLAN 0xF4FA | ||
165 | #define BIT_WLAN_ON 1 | ||
166 | #define BIT_WLAN_OFF 0 | ||
167 | #define REG_DISPLAY_LCD 0xF79F | ||
168 | |||
169 | /* SCI Event Number from EC */ | ||
170 | enum { | ||
171 | EVENT_LID = 0x23, /* LID open/close */ | ||
172 | EVENT_DISPLAY_TOGGLE, /* Fn+F3 for display switch */ | ||
173 | EVENT_SLEEP, /* Fn+F1 for entering sleep mode */ | ||
174 | EVENT_OVERTEMP, /* Over-temperature happened */ | ||
175 | EVENT_CRT_DETECT, /* CRT is connected */ | ||
176 | EVENT_CAMERA, /* Camera on/off */ | ||
177 | EVENT_USB_OC2, /* USB2 Over Current occurred */ | ||
178 | EVENT_USB_OC0, /* USB0 Over Current occurred */ | ||
179 | EVENT_BLACK_SCREEN, /* Turn on/off backlight */ | ||
180 | EVENT_AUDIO_MUTE, /* Mute on/off */ | ||
181 | EVENT_DISPLAY_BRIGHTNESS,/* LCD backlight brightness adjust */ | ||
182 | EVENT_AC_BAT, /* AC & Battery relative issue */ | ||
183 | EVENT_AUDIO_VOLUME, /* Volume adjust */ | ||
184 | EVENT_WLAN, /* Wlan on/off */ | ||
185 | EVENT_END | ||
186 | }; | ||
187 | |||
188 | #endif /* !_EC_KB3310B_H */ | ||
diff --git a/arch/mips/loongson/lemote-2f/irq.c b/arch/mips/loongson/lemote-2f/irq.c new file mode 100644 index 000000000000..77d32f9cf31e --- /dev/null +++ b/arch/mips/loongson/lemote-2f/irq.c | |||
@@ -0,0 +1,134 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007 Lemote Inc. | ||
3 | * Author: Fuxin Zhang, zhangfx@lemote.com | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
8 | * option) any later version. | ||
9 | */ | ||
10 | |||
11 | #include <linux/interrupt.h> | ||
12 | #include <linux/module.h> | ||
13 | |||
14 | #include <asm/irq_cpu.h> | ||
15 | #include <asm/i8259.h> | ||
16 | #include <asm/mipsregs.h> | ||
17 | |||
18 | #include <loongson.h> | ||
19 | #include <machine.h> | ||
20 | |||
21 | #define LOONGSON_TIMER_IRQ (MIPS_CPU_IRQ_BASE + 7) /* cpu timer */ | ||
22 | #define LOONGSON_PERFCNT_IRQ (MIPS_CPU_IRQ_BASE + 6) /* cpu perf counter */ | ||
23 | #define LOONGSON_NORTH_BRIDGE_IRQ (MIPS_CPU_IRQ_BASE + 6) /* bonito */ | ||
24 | #define LOONGSON_UART_IRQ (MIPS_CPU_IRQ_BASE + 3) /* cpu serial port */ | ||
25 | #define LOONGSON_SOUTH_BRIDGE_IRQ (MIPS_CPU_IRQ_BASE + 2) /* i8259 */ | ||
26 | |||
27 | #define LOONGSON_INT_BIT_INT0 (1 << 11) | ||
28 | #define LOONGSON_INT_BIT_INT1 (1 << 12) | ||
29 | |||
30 | /* | ||
31 | * The generic i8259_irq() make the kernel hang on booting. Since we cannot | ||
32 | * get the irq via the IRR directly, we access the ISR instead. | ||
33 | */ | ||
34 | int mach_i8259_irq(void) | ||
35 | { | ||
36 | int irq, isr; | ||
37 | |||
38 | irq = -1; | ||
39 | |||
40 | if ((LOONGSON_INTISR & LOONGSON_INTEN) & LOONGSON_INT_BIT_INT0) { | ||
41 | spin_lock(&i8259A_lock); | ||
42 | isr = inb(PIC_MASTER_CMD) & | ||
43 | ~inb(PIC_MASTER_IMR) & ~(1 << PIC_CASCADE_IR); | ||
44 | if (!isr) | ||
45 | isr = (inb(PIC_SLAVE_CMD) & ~inb(PIC_SLAVE_IMR)) << 8; | ||
46 | irq = ffs(isr) - 1; | ||
47 | if (unlikely(irq == 7)) { | ||
48 | /* | ||
49 | * This may be a spurious interrupt. | ||
50 | * | ||
51 | * Read the interrupt status register (ISR). If the most | ||
52 | * significant bit is not set then there is no valid | ||
53 | * interrupt. | ||
54 | */ | ||
55 | outb(0x0B, PIC_MASTER_ISR); /* ISR register */ | ||
56 | if (~inb(PIC_MASTER_ISR) & 0x80) | ||
57 | irq = -1; | ||
58 | } | ||
59 | spin_unlock(&i8259A_lock); | ||
60 | } | ||
61 | |||
62 | return irq; | ||
63 | } | ||
64 | EXPORT_SYMBOL(mach_i8259_irq); | ||
65 | |||
66 | static void i8259_irqdispatch(void) | ||
67 | { | ||
68 | int irq; | ||
69 | |||
70 | irq = mach_i8259_irq(); | ||
71 | if (irq >= 0) | ||
72 | do_IRQ(irq); | ||
73 | else | ||
74 | spurious_interrupt(); | ||
75 | } | ||
76 | |||
77 | void mach_irq_dispatch(unsigned int pending) | ||
78 | { | ||
79 | if (pending & CAUSEF_IP7) | ||
80 | do_IRQ(LOONGSON_TIMER_IRQ); | ||
81 | else if (pending & CAUSEF_IP6) { /* North Bridge, Perf counter */ | ||
82 | #ifdef CONFIG_OPROFILE | ||
83 | do_IRQ(LOONGSON2_PERFCNT_IRQ); | ||
84 | #endif | ||
85 | bonito_irqdispatch(); | ||
86 | } else if (pending & CAUSEF_IP3) /* CPU UART */ | ||
87 | do_IRQ(LOONGSON_UART_IRQ); | ||
88 | else if (pending & CAUSEF_IP2) /* South Bridge */ | ||
89 | i8259_irqdispatch(); | ||
90 | else | ||
91 | spurious_interrupt(); | ||
92 | } | ||
93 | |||
94 | void __init set_irq_trigger_mode(void) | ||
95 | { | ||
96 | /* setup cs5536 as high level trigger */ | ||
97 | LOONGSON_INTPOL = LOONGSON_INT_BIT_INT0 | LOONGSON_INT_BIT_INT1; | ||
98 | LOONGSON_INTEDGE &= ~(LOONGSON_INT_BIT_INT0 | LOONGSON_INT_BIT_INT1); | ||
99 | } | ||
100 | |||
101 | static irqreturn_t ip6_action(int cpl, void *dev_id) | ||
102 | { | ||
103 | return IRQ_HANDLED; | ||
104 | } | ||
105 | |||
106 | struct irqaction ip6_irqaction = { | ||
107 | .handler = ip6_action, | ||
108 | .name = "cascade", | ||
109 | .flags = IRQF_SHARED, | ||
110 | }; | ||
111 | |||
112 | struct irqaction cascade_irqaction = { | ||
113 | .handler = no_action, | ||
114 | .name = "cascade", | ||
115 | }; | ||
116 | |||
117 | void __init mach_init_irq(void) | ||
118 | { | ||
119 | /* init all controller | ||
120 | * 0-15 ------> i8259 interrupt | ||
121 | * 16-23 ------> mips cpu interrupt | ||
122 | * 32-63 ------> bonito irq | ||
123 | */ | ||
124 | |||
125 | /* Sets the first-level interrupt dispatcher. */ | ||
126 | mips_cpu_irq_init(); | ||
127 | init_i8259_irqs(); | ||
128 | bonito_irq_init(); | ||
129 | |||
130 | /* setup north bridge irq (bonito) */ | ||
131 | setup_irq(LOONGSON_NORTH_BRIDGE_IRQ, &ip6_irqaction); | ||
132 | /* setup source bridge irq (i8259) */ | ||
133 | setup_irq(LOONGSON_SOUTH_BRIDGE_IRQ, &cascade_irqaction); | ||
134 | } | ||
diff --git a/arch/mips/loongson/lemote-2f/pm.c b/arch/mips/loongson/lemote-2f/pm.c new file mode 100644 index 000000000000..d7af2e616592 --- /dev/null +++ b/arch/mips/loongson/lemote-2f/pm.c | |||
@@ -0,0 +1,149 @@ | |||
1 | /* | ||
2 | * Lemote loongson2f family machines' specific suspend support | ||
3 | * | ||
4 | * Copyright (C) 2009 Lemote Inc. | ||
5 | * Author: Wu Zhangjin <wuzj@lemote.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/suspend.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/pm.h> | ||
16 | #include <linux/i8042.h> | ||
17 | #include <linux/module.h> | ||
18 | |||
19 | #include <asm/i8259.h> | ||
20 | #include <asm/mipsregs.h> | ||
21 | #include <asm/bootinfo.h> | ||
22 | |||
23 | #include <loongson.h> | ||
24 | |||
25 | #include <cs5536/cs5536_mfgpt.h> | ||
26 | #include "ec_kb3310b.h" | ||
27 | |||
28 | #define I8042_KBD_IRQ 1 | ||
29 | #define I8042_CTR_KBDINT 0x01 | ||
30 | #define I8042_CTR_KBDDIS 0x10 | ||
31 | |||
32 | static unsigned char i8042_ctr; | ||
33 | |||
34 | static int i8042_enable_kbd_port(void) | ||
35 | { | ||
36 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) { | ||
37 | pr_err("i8042.c: Can't read CTR while enabling i8042 kbd port." | ||
38 | "\n"); | ||
39 | return -EIO; | ||
40 | } | ||
41 | |||
42 | i8042_ctr &= ~I8042_CTR_KBDDIS; | ||
43 | i8042_ctr |= I8042_CTR_KBDINT; | ||
44 | |||
45 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | ||
46 | i8042_ctr &= ~I8042_CTR_KBDINT; | ||
47 | i8042_ctr |= I8042_CTR_KBDDIS; | ||
48 | pr_err("i8042.c: Failed to enable KBD port.\n"); | ||
49 | |||
50 | return -EIO; | ||
51 | } | ||
52 | |||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | void setup_wakeup_events(void) | ||
57 | { | ||
58 | int irq_mask; | ||
59 | |||
60 | switch (mips_machtype) { | ||
61 | case MACH_LEMOTE_ML2F7: | ||
62 | case MACH_LEMOTE_YL2F89: | ||
63 | /* open the keyboard irq in i8259A */ | ||
64 | outb((0xff & ~(1 << I8042_KBD_IRQ)), PIC_MASTER_IMR); | ||
65 | irq_mask = inb(PIC_MASTER_IMR); | ||
66 | |||
67 | /* enable keyboard port */ | ||
68 | i8042_enable_kbd_port(); | ||
69 | |||
70 | /* Wakeup CPU via SCI lid open event */ | ||
71 | outb(irq_mask & ~(1 << PIC_CASCADE_IR), PIC_MASTER_IMR); | ||
72 | inb(PIC_MASTER_IMR); | ||
73 | outb(0xff & ~(1 << (SCI_IRQ_NUM - 8)), PIC_SLAVE_IMR); | ||
74 | inb(PIC_SLAVE_IMR); | ||
75 | |||
76 | break; | ||
77 | |||
78 | default: | ||
79 | break; | ||
80 | } | ||
81 | } | ||
82 | |||
83 | static struct delayed_work lid_task; | ||
84 | static int initialized; | ||
85 | /* yeeloong_report_lid_status will be implemented in yeeloong_laptop.c */ | ||
86 | sci_handler yeeloong_report_lid_status; | ||
87 | EXPORT_SYMBOL(yeeloong_report_lid_status); | ||
88 | static void yeeloong_lid_update_task(struct work_struct *work) | ||
89 | { | ||
90 | if (yeeloong_report_lid_status) | ||
91 | yeeloong_report_lid_status(BIT_LID_DETECT_ON); | ||
92 | } | ||
93 | |||
94 | int wakeup_loongson(void) | ||
95 | { | ||
96 | int irq; | ||
97 | |||
98 | /* query the interrupt number */ | ||
99 | irq = mach_i8259_irq(); | ||
100 | if (irq < 0) | ||
101 | return 0; | ||
102 | |||
103 | printk(KERN_INFO "%s: irq = %d\n", __func__, irq); | ||
104 | |||
105 | if (irq == I8042_KBD_IRQ) | ||
106 | return 1; | ||
107 | else if (irq == SCI_IRQ_NUM) { | ||
108 | int ret, sci_event; | ||
109 | /* query the event number */ | ||
110 | ret = ec_query_seq(CMD_GET_EVENT_NUM); | ||
111 | if (ret < 0) | ||
112 | return 0; | ||
113 | sci_event = ec_get_event_num(); | ||
114 | if (sci_event < 0) | ||
115 | return 0; | ||
116 | if (sci_event == EVENT_LID) { | ||
117 | int lid_status; | ||
118 | /* check the LID status */ | ||
119 | lid_status = ec_read(REG_LID_DETECT); | ||
120 | /* wakeup cpu when people open the LID */ | ||
121 | if (lid_status == BIT_LID_DETECT_ON) { | ||
122 | /* If we call it directly here, the WARNING | ||
123 | * will be sent out by getnstimeofday | ||
124 | * via "WARN_ON(timekeeping_suspended);" | ||
125 | * because we can not schedule in suspend mode. | ||
126 | */ | ||
127 | if (initialized == 0) { | ||
128 | INIT_DELAYED_WORK(&lid_task, | ||
129 | yeeloong_lid_update_task); | ||
130 | initialized = 1; | ||
131 | } | ||
132 | schedule_delayed_work(&lid_task, 1); | ||
133 | return 1; | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | void __weak mach_suspend(void) | ||
142 | { | ||
143 | disable_mfgpt0_counter(); | ||
144 | } | ||
145 | |||
146 | void __weak mach_resume(void) | ||
147 | { | ||
148 | enable_mfgpt0_counter(); | ||
149 | } | ||
diff --git a/arch/mips/loongson/lemote-2f/reset.c b/arch/mips/loongson/lemote-2f/reset.c new file mode 100644 index 000000000000..51d1a60d5349 --- /dev/null +++ b/arch/mips/loongson/lemote-2f/reset.c | |||
@@ -0,0 +1,159 @@ | |||
1 | /* Board-specific reboot/shutdown routines | ||
2 | * | ||
3 | * Copyright (c) 2009 Philippe Vachon <philippe@cowpig.ca> | ||
4 | * | ||
5 | * Copyright (C) 2009 Lemote Inc. | ||
6 | * Author: Wu Zhangjin, wuzj@lemote.com | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/io.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/types.h> | ||
17 | |||
18 | #include <asm/bootinfo.h> | ||
19 | |||
20 | #include <loongson.h> | ||
21 | |||
22 | #include <cs5536/cs5536.h> | ||
23 | #include "ec_kb3310b.h" | ||
24 | |||
25 | static void reset_cpu(void) | ||
26 | { | ||
27 | /* | ||
28 | * reset cpu to full speed, this is needed when enabling cpu frequency | ||
29 | * scalling | ||
30 | */ | ||
31 | LOONGSON_CHIPCFG0 |= 0x7; | ||
32 | } | ||
33 | |||
34 | /* reset support for fuloong2f */ | ||
35 | |||
36 | static void fl2f_reboot(void) | ||
37 | { | ||
38 | reset_cpu(); | ||
39 | |||
40 | /* send a reset signal to south bridge. | ||
41 | * | ||
42 | * NOTE: if enable "Power Management" in kernel, rtl8169 will not reset | ||
43 | * normally with this reset operation and it will not work in PMON, but | ||
44 | * you can type halt command and then reboot, seems the hardware reset | ||
45 | * logic not work normally. | ||
46 | */ | ||
47 | { | ||
48 | u32 hi, lo; | ||
49 | _rdmsr(DIVIL_MSR_REG(DIVIL_SOFT_RESET), &hi, &lo); | ||
50 | lo |= 0x00000001; | ||
51 | _wrmsr(DIVIL_MSR_REG(DIVIL_SOFT_RESET), hi, lo); | ||
52 | } | ||
53 | } | ||
54 | |||
55 | static void fl2f_shutdown(void) | ||
56 | { | ||
57 | u32 hi, lo, val; | ||
58 | int gpio_base; | ||
59 | |||
60 | /* get gpio base */ | ||
61 | _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &lo); | ||
62 | gpio_base = lo & 0xff00; | ||
63 | |||
64 | /* make cs5536 gpio13 output enable */ | ||
65 | val = inl(gpio_base + GPIOL_OUT_EN); | ||
66 | val &= ~(1 << (16 + 13)); | ||
67 | val |= (1 << 13); | ||
68 | outl(val, gpio_base + GPIOL_OUT_EN); | ||
69 | mmiowb(); | ||
70 | /* make cs5536 gpio13 output low level voltage. */ | ||
71 | val = inl(gpio_base + GPIOL_OUT_VAL) & ~(1 << (13)); | ||
72 | val |= (1 << (16 + 13)); | ||
73 | outl(val, gpio_base + GPIOL_OUT_VAL); | ||
74 | mmiowb(); | ||
75 | } | ||
76 | |||
77 | /* reset support for yeeloong2f and mengloong2f notebook */ | ||
78 | |||
79 | void ml2f_reboot(void) | ||
80 | { | ||
81 | reset_cpu(); | ||
82 | |||
83 | /* sending an reset signal to EC(embedded controller) */ | ||
84 | ec_write(REG_RESET, BIT_RESET_ON); | ||
85 | } | ||
86 | |||
87 | #define yl2f89_reboot ml2f_reboot | ||
88 | |||
89 | /* menglong(7inches) laptop has different shutdown logic from 8.9inches */ | ||
90 | #define EC_SHUTDOWN_IO_PORT_HIGH 0xff2d | ||
91 | #define EC_SHUTDOWN_IO_PORT_LOW 0xff2e | ||
92 | #define EC_SHUTDOWN_IO_PORT_DATA 0xff2f | ||
93 | #define REG_SHUTDOWN_HIGH 0xFC | ||
94 | #define REG_SHUTDOWN_LOW 0x29 | ||
95 | #define BIT_SHUTDOWN_ON (1 << 1) | ||
96 | |||
97 | static void ml2f_shutdown(void) | ||
98 | { | ||
99 | u8 val; | ||
100 | u64 i; | ||
101 | |||
102 | outb(REG_SHUTDOWN_HIGH, EC_SHUTDOWN_IO_PORT_HIGH); | ||
103 | outb(REG_SHUTDOWN_LOW, EC_SHUTDOWN_IO_PORT_LOW); | ||
104 | mmiowb(); | ||
105 | val = inb(EC_SHUTDOWN_IO_PORT_DATA); | ||
106 | outb(val & (~BIT_SHUTDOWN_ON), EC_SHUTDOWN_IO_PORT_DATA); | ||
107 | mmiowb(); | ||
108 | /* need enough wait here... how many microseconds needs? */ | ||
109 | for (i = 0; i < 0x10000; i++) | ||
110 | delay(); | ||
111 | outb(val | BIT_SHUTDOWN_ON, EC_SHUTDOWN_IO_PORT_DATA); | ||
112 | mmiowb(); | ||
113 | } | ||
114 | |||
115 | static void yl2f89_shutdown(void) | ||
116 | { | ||
117 | /* cpu-gpio0 output low */ | ||
118 | LOONGSON_GPIODATA &= ~0x00000001; | ||
119 | /* cpu-gpio0 as output */ | ||
120 | LOONGSON_GPIOIE &= ~0x00000001; | ||
121 | } | ||
122 | |||
123 | void mach_prepare_reboot(void) | ||
124 | { | ||
125 | switch (mips_machtype) { | ||
126 | case MACH_LEMOTE_FL2F: | ||
127 | case MACH_LEMOTE_NAS: | ||
128 | case MACH_LEMOTE_LL2F: | ||
129 | fl2f_reboot(); | ||
130 | break; | ||
131 | case MACH_LEMOTE_ML2F7: | ||
132 | ml2f_reboot(); | ||
133 | break; | ||
134 | case MACH_LEMOTE_YL2F89: | ||
135 | yl2f89_reboot(); | ||
136 | break; | ||
137 | default: | ||
138 | break; | ||
139 | } | ||
140 | } | ||
141 | |||
142 | void mach_prepare_shutdown(void) | ||
143 | { | ||
144 | switch (mips_machtype) { | ||
145 | case MACH_LEMOTE_FL2F: | ||
146 | case MACH_LEMOTE_NAS: | ||
147 | case MACH_LEMOTE_LL2F: | ||
148 | fl2f_shutdown(); | ||
149 | break; | ||
150 | case MACH_LEMOTE_ML2F7: | ||
151 | ml2f_shutdown(); | ||
152 | break; | ||
153 | case MACH_LEMOTE_YL2F89: | ||
154 | yl2f89_shutdown(); | ||
155 | break; | ||
156 | default: | ||
157 | break; | ||
158 | } | ||
159 | } | ||