diff options
Diffstat (limited to 'arch/mips/loongson32')
-rw-r--r-- | arch/mips/loongson32/Kconfig | 75 | ||||
-rw-r--r-- | arch/mips/loongson32/Makefile | 18 | ||||
-rw-r--r-- | arch/mips/loongson32/Platform | 3 | ||||
-rw-r--r-- | arch/mips/loongson32/common/Makefile | 6 | ||||
-rw-r--r-- | arch/mips/loongson32/common/irq.c | 191 | ||||
-rw-r--r-- | arch/mips/loongson32/common/platform.c | 311 | ||||
-rw-r--r-- | arch/mips/loongson32/common/prom.c | 46 | ||||
-rw-r--r-- | arch/mips/loongson32/common/reset.c | 51 | ||||
-rw-r--r-- | arch/mips/loongson32/common/setup.c | 26 | ||||
-rw-r--r-- | arch/mips/loongson32/common/time.c | 232 | ||||
-rw-r--r-- | arch/mips/loongson32/ls1b/Makefile | 6 | ||||
-rw-r--r-- | arch/mips/loongson32/ls1b/board.c | 58 | ||||
-rw-r--r-- | arch/mips/loongson32/ls1c/Makefile | 6 | ||||
-rw-r--r-- | arch/mips/loongson32/ls1c/board.c | 23 |
14 files changed, 1052 insertions, 0 deletions
diff --git a/arch/mips/loongson32/Kconfig b/arch/mips/loongson32/Kconfig new file mode 100644 index 000000000..e27879b48 --- /dev/null +++ b/arch/mips/loongson32/Kconfig | |||
@@ -0,0 +1,75 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | ||
2 | if MACH_LOONGSON32 | ||
3 | |||
4 | choice | ||
5 | prompt "Machine Type" | ||
6 | |||
7 | config LOONGSON1_LS1B | ||
8 | bool "Loongson LS1B board" | ||
9 | select CEVT_R4K if !MIPS_EXTERNAL_TIMER | ||
10 | select CSRC_R4K if !MIPS_EXTERNAL_TIMER | ||
11 | select SYS_HAS_CPU_LOONGSON1B | ||
12 | select DMA_NONCOHERENT | ||
13 | select BOOT_ELF32 | ||
14 | select IRQ_MIPS_CPU | ||
15 | select SYS_SUPPORTS_32BIT_KERNEL | ||
16 | select SYS_SUPPORTS_LITTLE_ENDIAN | ||
17 | select SYS_SUPPORTS_HIGHMEM | ||
18 | select SYS_HAS_EARLY_PRINTK | ||
19 | select USE_GENERIC_EARLY_PRINTK_8250 | ||
20 | select COMMON_CLK | ||
21 | |||
22 | config LOONGSON1_LS1C | ||
23 | bool "Loongson LS1C board" | ||
24 | select CEVT_R4K if !MIPS_EXTERNAL_TIMER | ||
25 | select CSRC_R4K if !MIPS_EXTERNAL_TIMER | ||
26 | select SYS_HAS_CPU_LOONGSON1C | ||
27 | select DMA_NONCOHERENT | ||
28 | select BOOT_ELF32 | ||
29 | select IRQ_MIPS_CPU | ||
30 | select SYS_SUPPORTS_32BIT_KERNEL | ||
31 | select SYS_SUPPORTS_LITTLE_ENDIAN | ||
32 | select SYS_SUPPORTS_HIGHMEM | ||
33 | select SYS_HAS_EARLY_PRINTK | ||
34 | select USE_GENERIC_EARLY_PRINTK_8250 | ||
35 | select COMMON_CLK | ||
36 | endchoice | ||
37 | |||
38 | menuconfig CEVT_CSRC_LS1X | ||
39 | bool "Use PWM Timer for clockevent/clocksource" | ||
40 | select MIPS_EXTERNAL_TIMER | ||
41 | depends on CPU_LOONGSON32 | ||
42 | help | ||
43 | This option changes the default clockevent/clocksource to PWM Timer, | ||
44 | and is required by Loongson1 CPUFreq support. | ||
45 | |||
46 | If unsure, say N. | ||
47 | |||
48 | choice | ||
49 | prompt "Select clockevent/clocksource" | ||
50 | depends on CEVT_CSRC_LS1X | ||
51 | default TIMER_USE_PWM0 | ||
52 | |||
53 | config TIMER_USE_PWM0 | ||
54 | bool "Use PWM Timer 0" | ||
55 | help | ||
56 | Use PWM Timer 0 as the default clockevent/clocksourcer. | ||
57 | |||
58 | config TIMER_USE_PWM1 | ||
59 | bool "Use PWM Timer 1" | ||
60 | help | ||
61 | Use PWM Timer 1 as the default clockevent/clocksourcer. | ||
62 | |||
63 | config TIMER_USE_PWM2 | ||
64 | bool "Use PWM Timer 2" | ||
65 | help | ||
66 | Use PWM Timer 2 as the default clockevent/clocksourcer. | ||
67 | |||
68 | config TIMER_USE_PWM3 | ||
69 | bool "Use PWM Timer 3" | ||
70 | help | ||
71 | Use PWM Timer 3 as the default clockevent/clocksourcer. | ||
72 | |||
73 | endchoice | ||
74 | |||
75 | endif # MACH_LOONGSON32 | ||
diff --git a/arch/mips/loongson32/Makefile b/arch/mips/loongson32/Makefile new file mode 100644 index 000000000..ba10954b4 --- /dev/null +++ b/arch/mips/loongson32/Makefile | |||
@@ -0,0 +1,18 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0-only | ||
2 | # | ||
3 | # Common code for all Loongson 1 based systems | ||
4 | # | ||
5 | |||
6 | obj-$(CONFIG_MACH_LOONGSON32) += common/ | ||
7 | |||
8 | # | ||
9 | # Loongson LS1B board | ||
10 | # | ||
11 | |||
12 | obj-$(CONFIG_LOONGSON1_LS1B) += ls1b/ | ||
13 | |||
14 | # | ||
15 | # Loongson LS1C board | ||
16 | # | ||
17 | |||
18 | obj-$(CONFIG_LOONGSON1_LS1C) += ls1c/ | ||
diff --git a/arch/mips/loongson32/Platform b/arch/mips/loongson32/Platform new file mode 100644 index 000000000..3b9673e7a --- /dev/null +++ b/arch/mips/loongson32/Platform | |||
@@ -0,0 +1,3 @@ | |||
1 | cflags-$(CONFIG_CPU_LOONGSON32) += -march=mips32r2 -Wa,--trap | ||
2 | cflags-$(CONFIG_MACH_LOONGSON32) += -I$(srctree)/arch/mips/include/asm/mach-loongson32 | ||
3 | load-$(CONFIG_CPU_LOONGSON32) += 0xffffffff80200000 | ||
diff --git a/arch/mips/loongson32/common/Makefile b/arch/mips/loongson32/common/Makefile new file mode 100644 index 000000000..7b49c8260 --- /dev/null +++ b/arch/mips/loongson32/common/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0-only | ||
2 | # | ||
3 | # Makefile for common code of loongson1 based machines. | ||
4 | # | ||
5 | |||
6 | obj-y += time.o irq.o platform.o prom.o reset.o setup.o | ||
diff --git a/arch/mips/loongson32/common/irq.c b/arch/mips/loongson32/common/irq.c new file mode 100644 index 000000000..9a50070f7 --- /dev/null +++ b/arch/mips/loongson32/common/irq.c | |||
@@ -0,0 +1,191 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
2 | /* | ||
3 | * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com> | ||
4 | */ | ||
5 | |||
6 | #include <linux/interrupt.h> | ||
7 | #include <linux/irq.h> | ||
8 | #include <asm/irq_cpu.h> | ||
9 | |||
10 | #include <loongson1.h> | ||
11 | #include <irq.h> | ||
12 | |||
13 | #define LS1X_INTC_REG(n, x) \ | ||
14 | ((void __iomem *)KSEG1ADDR(LS1X_INTC_BASE + (n * 0x18) + (x))) | ||
15 | |||
16 | #define LS1X_INTC_INTISR(n) LS1X_INTC_REG(n, 0x0) | ||
17 | #define LS1X_INTC_INTIEN(n) LS1X_INTC_REG(n, 0x4) | ||
18 | #define LS1X_INTC_INTSET(n) LS1X_INTC_REG(n, 0x8) | ||
19 | #define LS1X_INTC_INTCLR(n) LS1X_INTC_REG(n, 0xc) | ||
20 | #define LS1X_INTC_INTPOL(n) LS1X_INTC_REG(n, 0x10) | ||
21 | #define LS1X_INTC_INTEDGE(n) LS1X_INTC_REG(n, 0x14) | ||
22 | |||
23 | static void ls1x_irq_ack(struct irq_data *d) | ||
24 | { | ||
25 | unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f; | ||
26 | unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5; | ||
27 | |||
28 | __raw_writel(__raw_readl(LS1X_INTC_INTCLR(n)) | ||
29 | | (1 << bit), LS1X_INTC_INTCLR(n)); | ||
30 | } | ||
31 | |||
32 | static void ls1x_irq_mask(struct irq_data *d) | ||
33 | { | ||
34 | unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f; | ||
35 | unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5; | ||
36 | |||
37 | __raw_writel(__raw_readl(LS1X_INTC_INTIEN(n)) | ||
38 | & ~(1 << bit), LS1X_INTC_INTIEN(n)); | ||
39 | } | ||
40 | |||
41 | static void ls1x_irq_mask_ack(struct irq_data *d) | ||
42 | { | ||
43 | unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f; | ||
44 | unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5; | ||
45 | |||
46 | __raw_writel(__raw_readl(LS1X_INTC_INTIEN(n)) | ||
47 | & ~(1 << bit), LS1X_INTC_INTIEN(n)); | ||
48 | __raw_writel(__raw_readl(LS1X_INTC_INTCLR(n)) | ||
49 | | (1 << bit), LS1X_INTC_INTCLR(n)); | ||
50 | } | ||
51 | |||
52 | static void ls1x_irq_unmask(struct irq_data *d) | ||
53 | { | ||
54 | unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f; | ||
55 | unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5; | ||
56 | |||
57 | __raw_writel(__raw_readl(LS1X_INTC_INTIEN(n)) | ||
58 | | (1 << bit), LS1X_INTC_INTIEN(n)); | ||
59 | } | ||
60 | |||
61 | static int ls1x_irq_settype(struct irq_data *d, unsigned int type) | ||
62 | { | ||
63 | unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f; | ||
64 | unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5; | ||
65 | |||
66 | switch (type) { | ||
67 | case IRQ_TYPE_LEVEL_HIGH: | ||
68 | __raw_writel(__raw_readl(LS1X_INTC_INTPOL(n)) | ||
69 | | (1 << bit), LS1X_INTC_INTPOL(n)); | ||
70 | __raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n)) | ||
71 | & ~(1 << bit), LS1X_INTC_INTEDGE(n)); | ||
72 | break; | ||
73 | case IRQ_TYPE_LEVEL_LOW: | ||
74 | __raw_writel(__raw_readl(LS1X_INTC_INTPOL(n)) | ||
75 | & ~(1 << bit), LS1X_INTC_INTPOL(n)); | ||
76 | __raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n)) | ||
77 | & ~(1 << bit), LS1X_INTC_INTEDGE(n)); | ||
78 | break; | ||
79 | case IRQ_TYPE_EDGE_RISING: | ||
80 | __raw_writel(__raw_readl(LS1X_INTC_INTPOL(n)) | ||
81 | | (1 << bit), LS1X_INTC_INTPOL(n)); | ||
82 | __raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n)) | ||
83 | | (1 << bit), LS1X_INTC_INTEDGE(n)); | ||
84 | break; | ||
85 | case IRQ_TYPE_EDGE_FALLING: | ||
86 | __raw_writel(__raw_readl(LS1X_INTC_INTPOL(n)) | ||
87 | & ~(1 << bit), LS1X_INTC_INTPOL(n)); | ||
88 | __raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n)) | ||
89 | | (1 << bit), LS1X_INTC_INTEDGE(n)); | ||
90 | break; | ||
91 | case IRQ_TYPE_EDGE_BOTH: | ||
92 | __raw_writel(__raw_readl(LS1X_INTC_INTPOL(n)) | ||
93 | & ~(1 << bit), LS1X_INTC_INTPOL(n)); | ||
94 | __raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n)) | ||
95 | | (1 << bit), LS1X_INTC_INTEDGE(n)); | ||
96 | break; | ||
97 | case IRQ_TYPE_NONE: | ||
98 | break; | ||
99 | default: | ||
100 | return -EINVAL; | ||
101 | } | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | static struct irq_chip ls1x_irq_chip = { | ||
107 | .name = "LS1X-INTC", | ||
108 | .irq_ack = ls1x_irq_ack, | ||
109 | .irq_mask = ls1x_irq_mask, | ||
110 | .irq_mask_ack = ls1x_irq_mask_ack, | ||
111 | .irq_unmask = ls1x_irq_unmask, | ||
112 | .irq_set_type = ls1x_irq_settype, | ||
113 | }; | ||
114 | |||
115 | static void ls1x_irq_dispatch(int n) | ||
116 | { | ||
117 | u32 int_status, irq; | ||
118 | |||
119 | /* Get pending sources, masked by current enables */ | ||
120 | int_status = __raw_readl(LS1X_INTC_INTISR(n)) & | ||
121 | __raw_readl(LS1X_INTC_INTIEN(n)); | ||
122 | |||
123 | if (int_status) { | ||
124 | irq = LS1X_IRQ(n, __ffs(int_status)); | ||
125 | do_IRQ(irq); | ||
126 | } | ||
127 | } | ||
128 | |||
129 | asmlinkage void plat_irq_dispatch(void) | ||
130 | { | ||
131 | unsigned int pending; | ||
132 | |||
133 | pending = read_c0_cause() & read_c0_status() & ST0_IM; | ||
134 | |||
135 | if (pending & CAUSEF_IP7) | ||
136 | do_IRQ(TIMER_IRQ); | ||
137 | else if (pending & CAUSEF_IP2) | ||
138 | ls1x_irq_dispatch(0); /* INT0 */ | ||
139 | else if (pending & CAUSEF_IP3) | ||
140 | ls1x_irq_dispatch(1); /* INT1 */ | ||
141 | else if (pending & CAUSEF_IP4) | ||
142 | ls1x_irq_dispatch(2); /* INT2 */ | ||
143 | else if (pending & CAUSEF_IP5) | ||
144 | ls1x_irq_dispatch(3); /* INT3 */ | ||
145 | else if (pending & CAUSEF_IP6) | ||
146 | ls1x_irq_dispatch(4); /* INT4 */ | ||
147 | else | ||
148 | spurious_interrupt(); | ||
149 | |||
150 | } | ||
151 | |||
152 | static void __init ls1x_irq_init(int base) | ||
153 | { | ||
154 | int n; | ||
155 | |||
156 | /* Disable interrupts and clear pending, | ||
157 | * setup all IRQs as high level triggered | ||
158 | */ | ||
159 | for (n = 0; n < INTN; n++) { | ||
160 | __raw_writel(0x0, LS1X_INTC_INTIEN(n)); | ||
161 | __raw_writel(0xffffffff, LS1X_INTC_INTCLR(n)); | ||
162 | __raw_writel(0xffffffff, LS1X_INTC_INTPOL(n)); | ||
163 | /* set DMA0, DMA1 and DMA2 to edge trigger */ | ||
164 | __raw_writel(n ? 0x0 : 0xe000, LS1X_INTC_INTEDGE(n)); | ||
165 | } | ||
166 | |||
167 | |||
168 | for (n = base; n < NR_IRQS; n++) { | ||
169 | irq_set_chip_and_handler(n, &ls1x_irq_chip, | ||
170 | handle_level_irq); | ||
171 | } | ||
172 | |||
173 | if (request_irq(INT0_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL)) | ||
174 | pr_err("Failed to request irq %d (cascade)\n", INT0_IRQ); | ||
175 | if (request_irq(INT1_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL)) | ||
176 | pr_err("Failed to request irq %d (cascade)\n", INT1_IRQ); | ||
177 | if (request_irq(INT2_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL)) | ||
178 | pr_err("Failed to request irq %d (cascade)\n", INT2_IRQ); | ||
179 | if (request_irq(INT3_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL)) | ||
180 | pr_err("Failed to request irq %d (cascade)\n", INT3_IRQ); | ||
181 | #if defined(CONFIG_LOONGSON1_LS1C) | ||
182 | if (request_irq(INT4_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL)) | ||
183 | pr_err("Failed to request irq %d (cascade)\n", INT4_IRQ); | ||
184 | #endif | ||
185 | } | ||
186 | |||
187 | void __init arch_init_irq(void) | ||
188 | { | ||
189 | mips_cpu_irq_init(); | ||
190 | ls1x_irq_init(LS1X_IRQ_BASE); | ||
191 | } | ||
diff --git a/arch/mips/loongson32/common/platform.c b/arch/mips/loongson32/common/platform.c new file mode 100644 index 000000000..311dc1580 --- /dev/null +++ b/arch/mips/loongson32/common/platform.c | |||
@@ -0,0 +1,311 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
2 | /* | ||
3 | * Copyright (c) 2011-2016 Zhang, Keguang <keguang.zhang@gmail.com> | ||
4 | */ | ||
5 | |||
6 | #include <linux/clk.h> | ||
7 | #include <linux/dma-mapping.h> | ||
8 | #include <linux/err.h> | ||
9 | #include <linux/mtd/partitions.h> | ||
10 | #include <linux/sizes.h> | ||
11 | #include <linux/phy.h> | ||
12 | #include <linux/serial_8250.h> | ||
13 | #include <linux/stmmac.h> | ||
14 | #include <linux/usb/ehci_pdriver.h> | ||
15 | |||
16 | #include <platform.h> | ||
17 | #include <loongson1.h> | ||
18 | #include <cpufreq.h> | ||
19 | #include <dma.h> | ||
20 | #include <nand.h> | ||
21 | |||
22 | /* 8250/16550 compatible UART */ | ||
23 | #define LS1X_UART(_id) \ | ||
24 | { \ | ||
25 | .mapbase = LS1X_UART ## _id ## _BASE, \ | ||
26 | .irq = LS1X_UART ## _id ## _IRQ, \ | ||
27 | .iotype = UPIO_MEM, \ | ||
28 | .flags = UPF_IOREMAP | UPF_FIXED_TYPE, \ | ||
29 | .type = PORT_16550A, \ | ||
30 | } | ||
31 | |||
32 | static struct plat_serial8250_port ls1x_serial8250_pdata[] = { | ||
33 | LS1X_UART(0), | ||
34 | LS1X_UART(1), | ||
35 | LS1X_UART(2), | ||
36 | LS1X_UART(3), | ||
37 | {}, | ||
38 | }; | ||
39 | |||
40 | struct platform_device ls1x_uart_pdev = { | ||
41 | .name = "serial8250", | ||
42 | .id = PLAT8250_DEV_PLATFORM, | ||
43 | .dev = { | ||
44 | .platform_data = ls1x_serial8250_pdata, | ||
45 | }, | ||
46 | }; | ||
47 | |||
48 | void __init ls1x_serial_set_uartclk(struct platform_device *pdev) | ||
49 | { | ||
50 | struct clk *clk; | ||
51 | struct plat_serial8250_port *p; | ||
52 | |||
53 | clk = clk_get(&pdev->dev, pdev->name); | ||
54 | if (IS_ERR(clk)) { | ||
55 | pr_err("unable to get %s clock, err=%ld", | ||
56 | pdev->name, PTR_ERR(clk)); | ||
57 | return; | ||
58 | } | ||
59 | clk_prepare_enable(clk); | ||
60 | |||
61 | for (p = pdev->dev.platform_data; p->flags != 0; ++p) | ||
62 | p->uartclk = clk_get_rate(clk); | ||
63 | } | ||
64 | |||
65 | /* CPUFreq */ | ||
66 | static struct plat_ls1x_cpufreq ls1x_cpufreq_pdata = { | ||
67 | .clk_name = "cpu_clk", | ||
68 | .osc_clk_name = "osc_clk", | ||
69 | .max_freq = 266 * 1000, | ||
70 | .min_freq = 33 * 1000, | ||
71 | }; | ||
72 | |||
73 | struct platform_device ls1x_cpufreq_pdev = { | ||
74 | .name = "ls1x-cpufreq", | ||
75 | .dev = { | ||
76 | .platform_data = &ls1x_cpufreq_pdata, | ||
77 | }, | ||
78 | }; | ||
79 | |||
80 | /* Synopsys Ethernet GMAC */ | ||
81 | static struct stmmac_mdio_bus_data ls1x_mdio_bus_data = { | ||
82 | .phy_mask = 0, | ||
83 | }; | ||
84 | |||
85 | static struct stmmac_dma_cfg ls1x_eth_dma_cfg = { | ||
86 | .pbl = 1, | ||
87 | }; | ||
88 | |||
89 | int ls1x_eth_mux_init(struct platform_device *pdev, void *priv) | ||
90 | { | ||
91 | struct plat_stmmacenet_data *plat_dat = NULL; | ||
92 | u32 val; | ||
93 | |||
94 | val = __raw_readl(LS1X_MUX_CTRL1); | ||
95 | |||
96 | #if defined(CONFIG_LOONGSON1_LS1B) | ||
97 | plat_dat = dev_get_platdata(&pdev->dev); | ||
98 | if (plat_dat->bus_id) { | ||
99 | __raw_writel(__raw_readl(LS1X_MUX_CTRL0) | GMAC1_USE_UART1 | | ||
100 | GMAC1_USE_UART0, LS1X_MUX_CTRL0); | ||
101 | switch (plat_dat->phy_interface) { | ||
102 | case PHY_INTERFACE_MODE_RGMII: | ||
103 | val &= ~(GMAC1_USE_TXCLK | GMAC1_USE_PWM23); | ||
104 | break; | ||
105 | case PHY_INTERFACE_MODE_MII: | ||
106 | val |= (GMAC1_USE_TXCLK | GMAC1_USE_PWM23); | ||
107 | break; | ||
108 | default: | ||
109 | pr_err("unsupported mii mode %d\n", | ||
110 | plat_dat->phy_interface); | ||
111 | return -ENOTSUPP; | ||
112 | } | ||
113 | val &= ~GMAC1_SHUT; | ||
114 | } else { | ||
115 | switch (plat_dat->phy_interface) { | ||
116 | case PHY_INTERFACE_MODE_RGMII: | ||
117 | val &= ~(GMAC0_USE_TXCLK | GMAC0_USE_PWM01); | ||
118 | break; | ||
119 | case PHY_INTERFACE_MODE_MII: | ||
120 | val |= (GMAC0_USE_TXCLK | GMAC0_USE_PWM01); | ||
121 | break; | ||
122 | default: | ||
123 | pr_err("unsupported mii mode %d\n", | ||
124 | plat_dat->phy_interface); | ||
125 | return -ENOTSUPP; | ||
126 | } | ||
127 | val &= ~GMAC0_SHUT; | ||
128 | } | ||
129 | __raw_writel(val, LS1X_MUX_CTRL1); | ||
130 | #elif defined(CONFIG_LOONGSON1_LS1C) | ||
131 | plat_dat = dev_get_platdata(&pdev->dev); | ||
132 | |||
133 | val &= ~PHY_INTF_SELI; | ||
134 | if (plat_dat->phy_interface == PHY_INTERFACE_MODE_RMII) | ||
135 | val |= 0x4 << PHY_INTF_SELI_SHIFT; | ||
136 | __raw_writel(val, LS1X_MUX_CTRL1); | ||
137 | |||
138 | val = __raw_readl(LS1X_MUX_CTRL0); | ||
139 | __raw_writel(val & (~GMAC_SHUT), LS1X_MUX_CTRL0); | ||
140 | #endif | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static struct plat_stmmacenet_data ls1x_eth0_pdata = { | ||
146 | .bus_id = 0, | ||
147 | .phy_addr = -1, | ||
148 | #if defined(CONFIG_LOONGSON1_LS1B) | ||
149 | .phy_interface = PHY_INTERFACE_MODE_MII, | ||
150 | #elif defined(CONFIG_LOONGSON1_LS1C) | ||
151 | .phy_interface = PHY_INTERFACE_MODE_RMII, | ||
152 | #endif | ||
153 | .mdio_bus_data = &ls1x_mdio_bus_data, | ||
154 | .dma_cfg = &ls1x_eth_dma_cfg, | ||
155 | .has_gmac = 1, | ||
156 | .tx_coe = 1, | ||
157 | .rx_queues_to_use = 1, | ||
158 | .tx_queues_to_use = 1, | ||
159 | .init = ls1x_eth_mux_init, | ||
160 | }; | ||
161 | |||
162 | static struct resource ls1x_eth0_resources[] = { | ||
163 | [0] = { | ||
164 | .start = LS1X_GMAC0_BASE, | ||
165 | .end = LS1X_GMAC0_BASE + SZ_64K - 1, | ||
166 | .flags = IORESOURCE_MEM, | ||
167 | }, | ||
168 | [1] = { | ||
169 | .name = "macirq", | ||
170 | .start = LS1X_GMAC0_IRQ, | ||
171 | .flags = IORESOURCE_IRQ, | ||
172 | }, | ||
173 | }; | ||
174 | |||
175 | struct platform_device ls1x_eth0_pdev = { | ||
176 | .name = "stmmaceth", | ||
177 | .id = 0, | ||
178 | .num_resources = ARRAY_SIZE(ls1x_eth0_resources), | ||
179 | .resource = ls1x_eth0_resources, | ||
180 | .dev = { | ||
181 | .platform_data = &ls1x_eth0_pdata, | ||
182 | }, | ||
183 | }; | ||
184 | |||
185 | #ifdef CONFIG_LOONGSON1_LS1B | ||
186 | static struct plat_stmmacenet_data ls1x_eth1_pdata = { | ||
187 | .bus_id = 1, | ||
188 | .phy_addr = -1, | ||
189 | .phy_interface = PHY_INTERFACE_MODE_MII, | ||
190 | .mdio_bus_data = &ls1x_mdio_bus_data, | ||
191 | .dma_cfg = &ls1x_eth_dma_cfg, | ||
192 | .has_gmac = 1, | ||
193 | .tx_coe = 1, | ||
194 | .rx_queues_to_use = 1, | ||
195 | .tx_queues_to_use = 1, | ||
196 | .init = ls1x_eth_mux_init, | ||
197 | }; | ||
198 | |||
199 | static struct resource ls1x_eth1_resources[] = { | ||
200 | [0] = { | ||
201 | .start = LS1X_GMAC1_BASE, | ||
202 | .end = LS1X_GMAC1_BASE + SZ_64K - 1, | ||
203 | .flags = IORESOURCE_MEM, | ||
204 | }, | ||
205 | [1] = { | ||
206 | .name = "macirq", | ||
207 | .start = LS1X_GMAC1_IRQ, | ||
208 | .flags = IORESOURCE_IRQ, | ||
209 | }, | ||
210 | }; | ||
211 | |||
212 | struct platform_device ls1x_eth1_pdev = { | ||
213 | .name = "stmmaceth", | ||
214 | .id = 1, | ||
215 | .num_resources = ARRAY_SIZE(ls1x_eth1_resources), | ||
216 | .resource = ls1x_eth1_resources, | ||
217 | .dev = { | ||
218 | .platform_data = &ls1x_eth1_pdata, | ||
219 | }, | ||
220 | }; | ||
221 | #endif /* CONFIG_LOONGSON1_LS1B */ | ||
222 | |||
223 | /* GPIO */ | ||
224 | static struct resource ls1x_gpio0_resources[] = { | ||
225 | [0] = { | ||
226 | .start = LS1X_GPIO0_BASE, | ||
227 | .end = LS1X_GPIO0_BASE + SZ_4 - 1, | ||
228 | .flags = IORESOURCE_MEM, | ||
229 | }, | ||
230 | }; | ||
231 | |||
232 | struct platform_device ls1x_gpio0_pdev = { | ||
233 | .name = "ls1x-gpio", | ||
234 | .id = 0, | ||
235 | .num_resources = ARRAY_SIZE(ls1x_gpio0_resources), | ||
236 | .resource = ls1x_gpio0_resources, | ||
237 | }; | ||
238 | |||
239 | static struct resource ls1x_gpio1_resources[] = { | ||
240 | [0] = { | ||
241 | .start = LS1X_GPIO1_BASE, | ||
242 | .end = LS1X_GPIO1_BASE + SZ_4 - 1, | ||
243 | .flags = IORESOURCE_MEM, | ||
244 | }, | ||
245 | }; | ||
246 | |||
247 | struct platform_device ls1x_gpio1_pdev = { | ||
248 | .name = "ls1x-gpio", | ||
249 | .id = 1, | ||
250 | .num_resources = ARRAY_SIZE(ls1x_gpio1_resources), | ||
251 | .resource = ls1x_gpio1_resources, | ||
252 | }; | ||
253 | |||
254 | /* USB EHCI */ | ||
255 | static u64 ls1x_ehci_dmamask = DMA_BIT_MASK(32); | ||
256 | |||
257 | static struct resource ls1x_ehci_resources[] = { | ||
258 | [0] = { | ||
259 | .start = LS1X_EHCI_BASE, | ||
260 | .end = LS1X_EHCI_BASE + SZ_32K - 1, | ||
261 | .flags = IORESOURCE_MEM, | ||
262 | }, | ||
263 | [1] = { | ||
264 | .start = LS1X_EHCI_IRQ, | ||
265 | .flags = IORESOURCE_IRQ, | ||
266 | }, | ||
267 | }; | ||
268 | |||
269 | static struct usb_ehci_pdata ls1x_ehci_pdata = { | ||
270 | }; | ||
271 | |||
272 | struct platform_device ls1x_ehci_pdev = { | ||
273 | .name = "ehci-platform", | ||
274 | .id = -1, | ||
275 | .num_resources = ARRAY_SIZE(ls1x_ehci_resources), | ||
276 | .resource = ls1x_ehci_resources, | ||
277 | .dev = { | ||
278 | .dma_mask = &ls1x_ehci_dmamask, | ||
279 | .platform_data = &ls1x_ehci_pdata, | ||
280 | }, | ||
281 | }; | ||
282 | |||
283 | /* Real Time Clock */ | ||
284 | void __init ls1x_rtc_set_extclk(struct platform_device *pdev) | ||
285 | { | ||
286 | u32 val = __raw_readl(LS1X_RTC_CTRL); | ||
287 | |||
288 | if (!(val & RTC_EXTCLK_OK)) | ||
289 | __raw_writel(val | RTC_EXTCLK_EN, LS1X_RTC_CTRL); | ||
290 | } | ||
291 | |||
292 | struct platform_device ls1x_rtc_pdev = { | ||
293 | .name = "ls1x-rtc", | ||
294 | .id = -1, | ||
295 | }; | ||
296 | |||
297 | /* Watchdog */ | ||
298 | static struct resource ls1x_wdt_resources[] = { | ||
299 | { | ||
300 | .start = LS1X_WDT_BASE, | ||
301 | .end = LS1X_WDT_BASE + SZ_16 - 1, | ||
302 | .flags = IORESOURCE_MEM, | ||
303 | }, | ||
304 | }; | ||
305 | |||
306 | struct platform_device ls1x_wdt_pdev = { | ||
307 | .name = "ls1x-wdt", | ||
308 | .id = -1, | ||
309 | .num_resources = ARRAY_SIZE(ls1x_wdt_resources), | ||
310 | .resource = ls1x_wdt_resources, | ||
311 | }; | ||
diff --git a/arch/mips/loongson32/common/prom.c b/arch/mips/loongson32/common/prom.c new file mode 100644 index 000000000..c133b5adf --- /dev/null +++ b/arch/mips/loongson32/common/prom.c | |||
@@ -0,0 +1,46 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
2 | /* | ||
3 | * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com> | ||
4 | * | ||
5 | * Modified from arch/mips/pnx833x/common/prom.c. | ||
6 | */ | ||
7 | |||
8 | #include <linux/io.h> | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/memblock.h> | ||
11 | #include <linux/serial_reg.h> | ||
12 | #include <asm/fw/fw.h> | ||
13 | |||
14 | #include <loongson1.h> | ||
15 | |||
16 | unsigned long memsize; | ||
17 | |||
18 | void __init prom_init(void) | ||
19 | { | ||
20 | void __iomem *uart_base; | ||
21 | |||
22 | fw_init_cmdline(); | ||
23 | |||
24 | memsize = fw_getenvl("memsize"); | ||
25 | if(!memsize) | ||
26 | memsize = DEFAULT_MEMSIZE; | ||
27 | |||
28 | if (strstr(arcs_cmdline, "console=ttyS3")) | ||
29 | uart_base = ioremap(LS1X_UART3_BASE, 0x0f); | ||
30 | else if (strstr(arcs_cmdline, "console=ttyS2")) | ||
31 | uart_base = ioremap(LS1X_UART2_BASE, 0x0f); | ||
32 | else if (strstr(arcs_cmdline, "console=ttyS1")) | ||
33 | uart_base = ioremap(LS1X_UART1_BASE, 0x0f); | ||
34 | else | ||
35 | uart_base = ioremap(LS1X_UART0_BASE, 0x0f); | ||
36 | setup_8250_early_printk_port((unsigned long)uart_base, 0, 0); | ||
37 | } | ||
38 | |||
39 | void __init prom_free_prom_memory(void) | ||
40 | { | ||
41 | } | ||
42 | |||
43 | void __init plat_mem_setup(void) | ||
44 | { | ||
45 | memblock_add(0x0, (memsize << 20)); | ||
46 | } | ||
diff --git a/arch/mips/loongson32/common/reset.c b/arch/mips/loongson32/common/reset.c new file mode 100644 index 000000000..0c7399b30 --- /dev/null +++ b/arch/mips/loongson32/common/reset.c | |||
@@ -0,0 +1,51 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
2 | /* | ||
3 | * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com> | ||
4 | */ | ||
5 | |||
6 | #include <linux/io.h> | ||
7 | #include <linux/pm.h> | ||
8 | #include <linux/sizes.h> | ||
9 | #include <asm/idle.h> | ||
10 | #include <asm/reboot.h> | ||
11 | |||
12 | #include <loongson1.h> | ||
13 | |||
14 | static void __iomem *wdt_reg_base; | ||
15 | |||
16 | static void ls1x_halt(void) | ||
17 | { | ||
18 | while (1) { | ||
19 | if (cpu_wait) | ||
20 | cpu_wait(); | ||
21 | } | ||
22 | } | ||
23 | |||
24 | static void ls1x_restart(char *command) | ||
25 | { | ||
26 | __raw_writel(0x1, wdt_reg_base + WDT_EN); | ||
27 | __raw_writel(0x1, wdt_reg_base + WDT_TIMER); | ||
28 | __raw_writel(0x1, wdt_reg_base + WDT_SET); | ||
29 | |||
30 | ls1x_halt(); | ||
31 | } | ||
32 | |||
33 | static void ls1x_power_off(void) | ||
34 | { | ||
35 | ls1x_halt(); | ||
36 | } | ||
37 | |||
38 | static int __init ls1x_reboot_setup(void) | ||
39 | { | ||
40 | wdt_reg_base = ioremap(LS1X_WDT_BASE, (SZ_4 + SZ_8)); | ||
41 | if (!wdt_reg_base) | ||
42 | panic("Failed to remap watchdog registers"); | ||
43 | |||
44 | _machine_restart = ls1x_restart; | ||
45 | _machine_halt = ls1x_halt; | ||
46 | pm_power_off = ls1x_power_off; | ||
47 | |||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | arch_initcall(ls1x_reboot_setup); | ||
diff --git a/arch/mips/loongson32/common/setup.c b/arch/mips/loongson32/common/setup.c new file mode 100644 index 000000000..4733fe037 --- /dev/null +++ b/arch/mips/loongson32/common/setup.c | |||
@@ -0,0 +1,26 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
2 | /* | ||
3 | * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com> | ||
4 | */ | ||
5 | |||
6 | #include <linux/io.h> | ||
7 | #include <linux/init.h> | ||
8 | #include <linux/smp.h> | ||
9 | #include <asm/cpu-info.h> | ||
10 | #include <asm/bootinfo.h> | ||
11 | |||
12 | const char *get_system_type(void) | ||
13 | { | ||
14 | unsigned int processor_id = (¤t_cpu_data)->processor_id; | ||
15 | |||
16 | switch (processor_id & PRID_REV_MASK) { | ||
17 | case PRID_REV_LOONGSON1B: | ||
18 | #if defined(CONFIG_LOONGSON1_LS1B) | ||
19 | return "LOONGSON LS1B"; | ||
20 | #elif defined(CONFIG_LOONGSON1_LS1C) | ||
21 | return "LOONGSON LS1C"; | ||
22 | #endif | ||
23 | default: | ||
24 | return "LOONGSON (unknown)"; | ||
25 | } | ||
26 | } | ||
diff --git a/arch/mips/loongson32/common/time.c b/arch/mips/loongson32/common/time.c new file mode 100644 index 000000000..459b15c96 --- /dev/null +++ b/arch/mips/loongson32/common/time.c | |||
@@ -0,0 +1,232 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
2 | /* | ||
3 | * Copyright (c) 2014 Zhang, Keguang <keguang.zhang@gmail.com> | ||
4 | */ | ||
5 | |||
6 | #include <linux/clk.h> | ||
7 | #include <linux/interrupt.h> | ||
8 | #include <linux/sizes.h> | ||
9 | #include <asm/time.h> | ||
10 | |||
11 | #include <loongson1.h> | ||
12 | #include <platform.h> | ||
13 | |||
14 | #ifdef CONFIG_CEVT_CSRC_LS1X | ||
15 | |||
16 | #if defined(CONFIG_TIMER_USE_PWM1) | ||
17 | #define LS1X_TIMER_BASE LS1X_PWM1_BASE | ||
18 | #define LS1X_TIMER_IRQ LS1X_PWM1_IRQ | ||
19 | |||
20 | #elif defined(CONFIG_TIMER_USE_PWM2) | ||
21 | #define LS1X_TIMER_BASE LS1X_PWM2_BASE | ||
22 | #define LS1X_TIMER_IRQ LS1X_PWM2_IRQ | ||
23 | |||
24 | #elif defined(CONFIG_TIMER_USE_PWM3) | ||
25 | #define LS1X_TIMER_BASE LS1X_PWM3_BASE | ||
26 | #define LS1X_TIMER_IRQ LS1X_PWM3_IRQ | ||
27 | |||
28 | #else | ||
29 | #define LS1X_TIMER_BASE LS1X_PWM0_BASE | ||
30 | #define LS1X_TIMER_IRQ LS1X_PWM0_IRQ | ||
31 | #endif | ||
32 | |||
33 | DEFINE_RAW_SPINLOCK(ls1x_timer_lock); | ||
34 | |||
35 | static void __iomem *timer_reg_base; | ||
36 | static uint32_t ls1x_jiffies_per_tick; | ||
37 | |||
38 | static inline void ls1x_pwmtimer_set_period(uint32_t period) | ||
39 | { | ||
40 | __raw_writel(period, timer_reg_base + PWM_HRC); | ||
41 | __raw_writel(period, timer_reg_base + PWM_LRC); | ||
42 | } | ||
43 | |||
44 | static inline void ls1x_pwmtimer_restart(void) | ||
45 | { | ||
46 | __raw_writel(0x0, timer_reg_base + PWM_CNT); | ||
47 | __raw_writel(INT_EN | CNT_EN, timer_reg_base + PWM_CTRL); | ||
48 | } | ||
49 | |||
50 | void __init ls1x_pwmtimer_init(void) | ||
51 | { | ||
52 | timer_reg_base = ioremap(LS1X_TIMER_BASE, SZ_16); | ||
53 | if (!timer_reg_base) | ||
54 | panic("Failed to remap timer registers"); | ||
55 | |||
56 | ls1x_jiffies_per_tick = DIV_ROUND_CLOSEST(mips_hpt_frequency, HZ); | ||
57 | |||
58 | ls1x_pwmtimer_set_period(ls1x_jiffies_per_tick); | ||
59 | ls1x_pwmtimer_restart(); | ||
60 | } | ||
61 | |||
62 | static u64 ls1x_clocksource_read(struct clocksource *cs) | ||
63 | { | ||
64 | unsigned long flags; | ||
65 | int count; | ||
66 | u32 jifs; | ||
67 | static int old_count; | ||
68 | static u32 old_jifs; | ||
69 | |||
70 | raw_spin_lock_irqsave(&ls1x_timer_lock, flags); | ||
71 | /* | ||
72 | * Although our caller may have the read side of xtime_lock, | ||
73 | * this is now a seqlock, and we are cheating in this routine | ||
74 | * by having side effects on state that we cannot undo if | ||
75 | * there is a collision on the seqlock and our caller has to | ||
76 | * retry. (Namely, old_jifs and old_count.) So we must treat | ||
77 | * jiffies as volatile despite the lock. We read jiffies | ||
78 | * before latching the timer count to guarantee that although | ||
79 | * the jiffies value might be older than the count (that is, | ||
80 | * the counter may underflow between the last point where | ||
81 | * jiffies was incremented and the point where we latch the | ||
82 | * count), it cannot be newer. | ||
83 | */ | ||
84 | jifs = jiffies; | ||
85 | /* read the count */ | ||
86 | count = __raw_readl(timer_reg_base + PWM_CNT); | ||
87 | |||
88 | /* | ||
89 | * It's possible for count to appear to go the wrong way for this | ||
90 | * reason: | ||
91 | * | ||
92 | * The timer counter underflows, but we haven't handled the resulting | ||
93 | * interrupt and incremented jiffies yet. | ||
94 | * | ||
95 | * Previous attempts to handle these cases intelligently were buggy, so | ||
96 | * we just do the simple thing now. | ||
97 | */ | ||
98 | if (count < old_count && jifs == old_jifs) | ||
99 | count = old_count; | ||
100 | |||
101 | old_count = count; | ||
102 | old_jifs = jifs; | ||
103 | |||
104 | raw_spin_unlock_irqrestore(&ls1x_timer_lock, flags); | ||
105 | |||
106 | return (u64) (jifs * ls1x_jiffies_per_tick) + count; | ||
107 | } | ||
108 | |||
109 | static struct clocksource ls1x_clocksource = { | ||
110 | .name = "ls1x-pwmtimer", | ||
111 | .read = ls1x_clocksource_read, | ||
112 | .mask = CLOCKSOURCE_MASK(24), | ||
113 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
114 | }; | ||
115 | |||
116 | static irqreturn_t ls1x_clockevent_isr(int irq, void *devid) | ||
117 | { | ||
118 | struct clock_event_device *cd = devid; | ||
119 | |||
120 | ls1x_pwmtimer_restart(); | ||
121 | cd->event_handler(cd); | ||
122 | |||
123 | return IRQ_HANDLED; | ||
124 | } | ||
125 | |||
126 | static int ls1x_clockevent_set_state_periodic(struct clock_event_device *cd) | ||
127 | { | ||
128 | raw_spin_lock(&ls1x_timer_lock); | ||
129 | ls1x_pwmtimer_set_period(ls1x_jiffies_per_tick); | ||
130 | ls1x_pwmtimer_restart(); | ||
131 | __raw_writel(INT_EN | CNT_EN, timer_reg_base + PWM_CTRL); | ||
132 | raw_spin_unlock(&ls1x_timer_lock); | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static int ls1x_clockevent_tick_resume(struct clock_event_device *cd) | ||
138 | { | ||
139 | raw_spin_lock(&ls1x_timer_lock); | ||
140 | __raw_writel(INT_EN | CNT_EN, timer_reg_base + PWM_CTRL); | ||
141 | raw_spin_unlock(&ls1x_timer_lock); | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | static int ls1x_clockevent_set_state_shutdown(struct clock_event_device *cd) | ||
147 | { | ||
148 | raw_spin_lock(&ls1x_timer_lock); | ||
149 | __raw_writel(__raw_readl(timer_reg_base + PWM_CTRL) & ~CNT_EN, | ||
150 | timer_reg_base + PWM_CTRL); | ||
151 | raw_spin_unlock(&ls1x_timer_lock); | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | static int ls1x_clockevent_set_next(unsigned long evt, | ||
157 | struct clock_event_device *cd) | ||
158 | { | ||
159 | raw_spin_lock(&ls1x_timer_lock); | ||
160 | ls1x_pwmtimer_set_period(evt); | ||
161 | ls1x_pwmtimer_restart(); | ||
162 | raw_spin_unlock(&ls1x_timer_lock); | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static struct clock_event_device ls1x_clockevent = { | ||
168 | .name = "ls1x-pwmtimer", | ||
169 | .features = CLOCK_EVT_FEAT_PERIODIC, | ||
170 | .rating = 300, | ||
171 | .irq = LS1X_TIMER_IRQ, | ||
172 | .set_next_event = ls1x_clockevent_set_next, | ||
173 | .set_state_shutdown = ls1x_clockevent_set_state_shutdown, | ||
174 | .set_state_periodic = ls1x_clockevent_set_state_periodic, | ||
175 | .set_state_oneshot = ls1x_clockevent_set_state_shutdown, | ||
176 | .tick_resume = ls1x_clockevent_tick_resume, | ||
177 | }; | ||
178 | |||
179 | static void __init ls1x_time_init(void) | ||
180 | { | ||
181 | struct clock_event_device *cd = &ls1x_clockevent; | ||
182 | int ret; | ||
183 | |||
184 | if (!mips_hpt_frequency) | ||
185 | panic("Invalid timer clock rate"); | ||
186 | |||
187 | ls1x_pwmtimer_init(); | ||
188 | |||
189 | clockevent_set_clock(cd, mips_hpt_frequency); | ||
190 | cd->max_delta_ns = clockevent_delta2ns(0xffffff, cd); | ||
191 | cd->max_delta_ticks = 0xffffff; | ||
192 | cd->min_delta_ns = clockevent_delta2ns(0x000300, cd); | ||
193 | cd->min_delta_ticks = 0x000300; | ||
194 | cd->cpumask = cpumask_of(smp_processor_id()); | ||
195 | clockevents_register_device(cd); | ||
196 | |||
197 | ls1x_clocksource.rating = 200 + mips_hpt_frequency / 10000000; | ||
198 | ret = clocksource_register_hz(&ls1x_clocksource, mips_hpt_frequency); | ||
199 | if (ret) | ||
200 | panic(KERN_ERR "Failed to register clocksource: %d\n", ret); | ||
201 | |||
202 | if (request_irq(LS1X_TIMER_IRQ, ls1x_clockevent_isr, | ||
203 | IRQF_PERCPU | IRQF_TIMER, "ls1x-pwmtimer", | ||
204 | &ls1x_clockevent)) | ||
205 | pr_err("Failed to register ls1x-pwmtimer interrupt\n"); | ||
206 | } | ||
207 | #endif /* CONFIG_CEVT_CSRC_LS1X */ | ||
208 | |||
209 | void __init plat_time_init(void) | ||
210 | { | ||
211 | struct clk *clk = NULL; | ||
212 | |||
213 | /* initialize LS1X clocks */ | ||
214 | ls1x_clk_init(); | ||
215 | |||
216 | #ifdef CONFIG_CEVT_CSRC_LS1X | ||
217 | /* setup LS1X PWM timer */ | ||
218 | clk = clk_get(NULL, "ls1x-pwmtimer"); | ||
219 | if (IS_ERR(clk)) | ||
220 | panic("unable to get timer clock, err=%ld", PTR_ERR(clk)); | ||
221 | |||
222 | mips_hpt_frequency = clk_get_rate(clk); | ||
223 | ls1x_time_init(); | ||
224 | #else | ||
225 | /* setup mips r4k timer */ | ||
226 | clk = clk_get(NULL, "cpu_clk"); | ||
227 | if (IS_ERR(clk)) | ||
228 | panic("unable to get cpu clock, err=%ld", PTR_ERR(clk)); | ||
229 | |||
230 | mips_hpt_frequency = clk_get_rate(clk) / 2; | ||
231 | #endif /* CONFIG_CEVT_CSRC_LS1X */ | ||
232 | } | ||
diff --git a/arch/mips/loongson32/ls1b/Makefile b/arch/mips/loongson32/ls1b/Makefile new file mode 100644 index 000000000..33c574dc0 --- /dev/null +++ b/arch/mips/loongson32/ls1b/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0-only | ||
2 | # | ||
3 | # Makefile for loongson1B based machines. | ||
4 | # | ||
5 | |||
6 | obj-y += board.o | ||
diff --git a/arch/mips/loongson32/ls1b/board.c b/arch/mips/loongson32/ls1b/board.c new file mode 100644 index 000000000..727e06718 --- /dev/null +++ b/arch/mips/loongson32/ls1b/board.c | |||
@@ -0,0 +1,58 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
2 | /* | ||
3 | * Copyright (c) 2011-2016 Zhang, Keguang <keguang.zhang@gmail.com> | ||
4 | */ | ||
5 | |||
6 | #include <linux/leds.h> | ||
7 | #include <linux/mtd/partitions.h> | ||
8 | #include <linux/sizes.h> | ||
9 | |||
10 | #include <loongson1.h> | ||
11 | #include <dma.h> | ||
12 | #include <nand.h> | ||
13 | #include <platform.h> | ||
14 | |||
15 | static const struct gpio_led ls1x_gpio_leds[] __initconst = { | ||
16 | { | ||
17 | .name = "LED9", | ||
18 | .default_trigger = "heartbeat", | ||
19 | .gpio = 38, | ||
20 | .active_low = 1, | ||
21 | .default_state = LEDS_GPIO_DEFSTATE_OFF, | ||
22 | }, { | ||
23 | .name = "LED6", | ||
24 | .default_trigger = "nand-disk", | ||
25 | .gpio = 39, | ||
26 | .active_low = 1, | ||
27 | .default_state = LEDS_GPIO_DEFSTATE_OFF, | ||
28 | }, | ||
29 | }; | ||
30 | |||
31 | static const struct gpio_led_platform_data ls1x_led_pdata __initconst = { | ||
32 | .num_leds = ARRAY_SIZE(ls1x_gpio_leds), | ||
33 | .leds = ls1x_gpio_leds, | ||
34 | }; | ||
35 | |||
36 | static struct platform_device *ls1b_platform_devices[] __initdata = { | ||
37 | &ls1x_uart_pdev, | ||
38 | &ls1x_cpufreq_pdev, | ||
39 | &ls1x_eth0_pdev, | ||
40 | &ls1x_eth1_pdev, | ||
41 | &ls1x_ehci_pdev, | ||
42 | &ls1x_gpio0_pdev, | ||
43 | &ls1x_gpio1_pdev, | ||
44 | &ls1x_rtc_pdev, | ||
45 | &ls1x_wdt_pdev, | ||
46 | }; | ||
47 | |||
48 | static int __init ls1b_platform_init(void) | ||
49 | { | ||
50 | ls1x_serial_set_uartclk(&ls1x_uart_pdev); | ||
51 | |||
52 | gpio_led_register_device(-1, &ls1x_led_pdata); | ||
53 | |||
54 | return platform_add_devices(ls1b_platform_devices, | ||
55 | ARRAY_SIZE(ls1b_platform_devices)); | ||
56 | } | ||
57 | |||
58 | arch_initcall(ls1b_platform_init); | ||
diff --git a/arch/mips/loongson32/ls1c/Makefile b/arch/mips/loongson32/ls1c/Makefile new file mode 100644 index 000000000..1cf3aa264 --- /dev/null +++ b/arch/mips/loongson32/ls1c/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0-only | ||
2 | # | ||
3 | # Makefile for loongson1C based machines. | ||
4 | # | ||
5 | |||
6 | obj-y += board.o | ||
diff --git a/arch/mips/loongson32/ls1c/board.c b/arch/mips/loongson32/ls1c/board.c new file mode 100644 index 000000000..9dcfe9de5 --- /dev/null +++ b/arch/mips/loongson32/ls1c/board.c | |||
@@ -0,0 +1,23 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
2 | /* | ||
3 | * Copyright (c) 2016 Yang Ling <gnaygnil@gmail.com> | ||
4 | */ | ||
5 | |||
6 | #include <platform.h> | ||
7 | |||
8 | static struct platform_device *ls1c_platform_devices[] __initdata = { | ||
9 | &ls1x_uart_pdev, | ||
10 | &ls1x_eth0_pdev, | ||
11 | &ls1x_rtc_pdev, | ||
12 | &ls1x_wdt_pdev, | ||
13 | }; | ||
14 | |||
15 | static int __init ls1c_platform_init(void) | ||
16 | { | ||
17 | ls1x_serial_set_uartclk(&ls1x_uart_pdev); | ||
18 | |||
19 | return platform_add_devices(ls1c_platform_devices, | ||
20 | ARRAY_SIZE(ls1c_platform_devices)); | ||
21 | } | ||
22 | |||
23 | arch_initcall(ls1c_platform_init); | ||