diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/mips/sibyte/swarm |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/mips/sibyte/swarm')
-rw-r--r-- | arch/mips/sibyte/swarm/Makefile | 3 | ||||
-rw-r--r-- | arch/mips/sibyte/swarm/dbg_io.c | 76 | ||||
-rw-r--r-- | arch/mips/sibyte/swarm/rtc_m41t81.c | 224 | ||||
-rw-r--r-- | arch/mips/sibyte/swarm/rtc_xicor1241.c | 203 | ||||
-rw-r--r-- | arch/mips/sibyte/swarm/setup.c | 163 | ||||
-rw-r--r-- | arch/mips/sibyte/swarm/time.c | 244 |
6 files changed, 913 insertions, 0 deletions
diff --git a/arch/mips/sibyte/swarm/Makefile b/arch/mips/sibyte/swarm/Makefile new file mode 100644 index 000000000000..2d626039195c --- /dev/null +++ b/arch/mips/sibyte/swarm/Makefile | |||
@@ -0,0 +1,3 @@ | |||
1 | lib-y = setup.o rtc_xicor1241.o rtc_m41t81.o | ||
2 | |||
3 | lib-$(CONFIG_KGDB) += dbg_io.o | ||
diff --git a/arch/mips/sibyte/swarm/dbg_io.c b/arch/mips/sibyte/swarm/dbg_io.c new file mode 100644 index 000000000000..75ce14c8eb69 --- /dev/null +++ b/arch/mips/sibyte/swarm/dbg_io.c | |||
@@ -0,0 +1,76 @@ | |||
1 | /* | ||
2 | * kgdb debug routines for SiByte boards. | ||
3 | * | ||
4 | * Copyright (C) 2001 MontaVista Software Inc. | ||
5 | * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | /* -------------------- BEGINNING OF CONFIG --------------------- */ | ||
15 | |||
16 | #include <linux/delay.h> | ||
17 | #include <asm/io.h> | ||
18 | #include <asm/sibyte/sb1250.h> | ||
19 | #include <asm/sibyte/sb1250_regs.h> | ||
20 | #include <asm/sibyte/sb1250_uart.h> | ||
21 | #include <asm/sibyte/sb1250_int.h> | ||
22 | #include <asm/addrspace.h> | ||
23 | |||
24 | /* | ||
25 | * We use the second serial port for kgdb traffic. | ||
26 | * 115200, 8, N, 1. | ||
27 | */ | ||
28 | |||
29 | #define BAUD_RATE 115200 | ||
30 | #define CLK_DIVISOR V_DUART_BAUD_RATE(BAUD_RATE) | ||
31 | #define DATA_BITS V_DUART_BITS_PER_CHAR_8 /* or 7 */ | ||
32 | #define PARITY V_DUART_PARITY_MODE_NONE /* or even */ | ||
33 | #define STOP_BITS M_DUART_STOP_BIT_LEN_1 /* or 2 */ | ||
34 | |||
35 | static int duart_initialized = 0; /* 0: need to be init'ed by kgdb */ | ||
36 | |||
37 | /* -------------------- END OF CONFIG --------------------- */ | ||
38 | extern int kgdb_port; | ||
39 | |||
40 | #define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg))) | ||
41 | #define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg))) | ||
42 | |||
43 | void putDebugChar(unsigned char c); | ||
44 | unsigned char getDebugChar(void); | ||
45 | static void | ||
46 | duart_init(int clk_divisor, int data, int parity, int stop) | ||
47 | { | ||
48 | duart_out(R_DUART_MODE_REG_1, data | parity); | ||
49 | duart_out(R_DUART_MODE_REG_2, stop); | ||
50 | duart_out(R_DUART_CLK_SEL, clk_divisor); | ||
51 | |||
52 | duart_out(R_DUART_CMD, M_DUART_RX_EN | M_DUART_TX_EN); /* enable rx and tx */ | ||
53 | } | ||
54 | |||
55 | void | ||
56 | putDebugChar(unsigned char c) | ||
57 | { | ||
58 | if (!duart_initialized) { | ||
59 | duart_initialized = 1; | ||
60 | duart_init(CLK_DIVISOR, DATA_BITS, PARITY, STOP_BITS); | ||
61 | } | ||
62 | while ((duart_in(R_DUART_STATUS) & M_DUART_TX_RDY) == 0); | ||
63 | duart_out(R_DUART_TX_HOLD, c); | ||
64 | } | ||
65 | |||
66 | unsigned char | ||
67 | getDebugChar(void) | ||
68 | { | ||
69 | if (!duart_initialized) { | ||
70 | duart_initialized = 1; | ||
71 | duart_init(CLK_DIVISOR, DATA_BITS, PARITY, STOP_BITS); | ||
72 | } | ||
73 | while ((duart_in(R_DUART_STATUS) & M_DUART_RX_RDY) == 0) ; | ||
74 | return duart_in(R_DUART_RX_HOLD); | ||
75 | } | ||
76 | |||
diff --git a/arch/mips/sibyte/swarm/rtc_m41t81.c b/arch/mips/sibyte/swarm/rtc_m41t81.c new file mode 100644 index 000000000000..0e633ee8d83c --- /dev/null +++ b/arch/mips/sibyte/swarm/rtc_m41t81.c | |||
@@ -0,0 +1,224 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000, 2001 Broadcom Corporation | ||
3 | * | ||
4 | * Copyright (C) 2002 MontaVista Software Inc. | ||
5 | * Author: jsun@mvista.com or jsun@junsun.net | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | */ | ||
13 | #include <linux/bcd.h> | ||
14 | #include <linux/types.h> | ||
15 | #include <linux/time.h> | ||
16 | |||
17 | #include <asm/time.h> | ||
18 | #include <asm/addrspace.h> | ||
19 | #include <asm/io.h> | ||
20 | |||
21 | #include <asm/sibyte/sb1250.h> | ||
22 | #include <asm/sibyte/sb1250_regs.h> | ||
23 | #include <asm/sibyte/sb1250_smbus.h> | ||
24 | |||
25 | |||
26 | /* M41T81 definitions */ | ||
27 | |||
28 | /* | ||
29 | * Register bits | ||
30 | */ | ||
31 | |||
32 | #define M41T81REG_SC_ST 0x80 /* stop bit */ | ||
33 | #define M41T81REG_HR_CB 0x40 /* century bit */ | ||
34 | #define M41T81REG_HR_CEB 0x80 /* century enable bit */ | ||
35 | #define M41T81REG_CTL_S 0x20 /* sign bit */ | ||
36 | #define M41T81REG_CTL_FT 0x40 /* frequency test bit */ | ||
37 | #define M41T81REG_CTL_OUT 0x80 /* output level */ | ||
38 | #define M41T81REG_WD_RB0 0x01 /* watchdog resolution bit 0 */ | ||
39 | #define M41T81REG_WD_RB1 0x02 /* watchdog resolution bit 1 */ | ||
40 | #define M41T81REG_WD_BMB0 0x04 /* watchdog multiplier bit 0 */ | ||
41 | #define M41T81REG_WD_BMB1 0x08 /* watchdog multiplier bit 1 */ | ||
42 | #define M41T81REG_WD_BMB2 0x10 /* watchdog multiplier bit 2 */ | ||
43 | #define M41T81REG_WD_BMB3 0x20 /* watchdog multiplier bit 3 */ | ||
44 | #define M41T81REG_WD_BMB4 0x40 /* watchdog multiplier bit 4 */ | ||
45 | #define M41T81REG_AMO_ABE 0x20 /* alarm in "battery back-up mode" enable bit */ | ||
46 | #define M41T81REG_AMO_SQWE 0x40 /* square wave enable */ | ||
47 | #define M41T81REG_AMO_AFE 0x80 /* alarm flag enable flag */ | ||
48 | #define M41T81REG_ADT_RPT5 0x40 /* alarm repeat mode bit 5 */ | ||
49 | #define M41T81REG_ADT_RPT4 0x80 /* alarm repeat mode bit 4 */ | ||
50 | #define M41T81REG_AHR_RPT3 0x80 /* alarm repeat mode bit 3 */ | ||
51 | #define M41T81REG_AHR_HT 0x40 /* halt update bit */ | ||
52 | #define M41T81REG_AMN_RPT2 0x80 /* alarm repeat mode bit 2 */ | ||
53 | #define M41T81REG_ASC_RPT1 0x80 /* alarm repeat mode bit 1 */ | ||
54 | #define M41T81REG_FLG_AF 0x40 /* alarm flag (read only) */ | ||
55 | #define M41T81REG_FLG_WDF 0x80 /* watchdog flag (read only) */ | ||
56 | #define M41T81REG_SQW_RS0 0x10 /* sqw frequency bit 0 */ | ||
57 | #define M41T81REG_SQW_RS1 0x20 /* sqw frequency bit 1 */ | ||
58 | #define M41T81REG_SQW_RS2 0x40 /* sqw frequency bit 2 */ | ||
59 | #define M41T81REG_SQW_RS3 0x80 /* sqw frequency bit 3 */ | ||
60 | |||
61 | |||
62 | /* | ||
63 | * Register numbers | ||
64 | */ | ||
65 | |||
66 | #define M41T81REG_TSC 0x00 /* tenths/hundredths of second */ | ||
67 | #define M41T81REG_SC 0x01 /* seconds */ | ||
68 | #define M41T81REG_MN 0x02 /* minute */ | ||
69 | #define M41T81REG_HR 0x03 /* hour/century */ | ||
70 | #define M41T81REG_DY 0x04 /* day of week */ | ||
71 | #define M41T81REG_DT 0x05 /* date of month */ | ||
72 | #define M41T81REG_MO 0x06 /* month */ | ||
73 | #define M41T81REG_YR 0x07 /* year */ | ||
74 | #define M41T81REG_CTL 0x08 /* control */ | ||
75 | #define M41T81REG_WD 0x09 /* watchdog */ | ||
76 | #define M41T81REG_AMO 0x0A /* alarm: month */ | ||
77 | #define M41T81REG_ADT 0x0B /* alarm: date */ | ||
78 | #define M41T81REG_AHR 0x0C /* alarm: hour */ | ||
79 | #define M41T81REG_AMN 0x0D /* alarm: minute */ | ||
80 | #define M41T81REG_ASC 0x0E /* alarm: second */ | ||
81 | #define M41T81REG_FLG 0x0F /* flags */ | ||
82 | #define M41T81REG_SQW 0x13 /* square wave register */ | ||
83 | |||
84 | #define M41T81_CCR_ADDRESS 0x68 | ||
85 | #define SMB_CSR(reg) ((u8 *) (IOADDR(A_SMB_REGISTER(1, reg)))) | ||
86 | |||
87 | static int m41t81_read(uint8_t addr) | ||
88 | { | ||
89 | while (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) | ||
90 | ; | ||
91 | |||
92 | bus_writeq(addr & 0xff, SMB_CSR(R_SMB_CMD)); | ||
93 | bus_writeq((V_SMB_ADDR(M41T81_CCR_ADDRESS) | V_SMB_TT_WR1BYTE), | ||
94 | SMB_CSR(R_SMB_START)); | ||
95 | |||
96 | while (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) | ||
97 | ; | ||
98 | |||
99 | bus_writeq((V_SMB_ADDR(M41T81_CCR_ADDRESS) | V_SMB_TT_RD1BYTE), | ||
100 | SMB_CSR(R_SMB_START)); | ||
101 | |||
102 | while (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) | ||
103 | ; | ||
104 | |||
105 | if (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) { | ||
106 | /* Clear error bit by writing a 1 */ | ||
107 | bus_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS)); | ||
108 | return -1; | ||
109 | } | ||
110 | |||
111 | return (bus_readq(SMB_CSR(R_SMB_DATA)) & 0xff); | ||
112 | } | ||
113 | |||
114 | static int m41t81_write(uint8_t addr, int b) | ||
115 | { | ||
116 | while (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) | ||
117 | ; | ||
118 | |||
119 | bus_writeq((addr & 0xFF), SMB_CSR(R_SMB_CMD)); | ||
120 | bus_writeq((b & 0xff), SMB_CSR(R_SMB_DATA)); | ||
121 | bus_writeq(V_SMB_ADDR(M41T81_CCR_ADDRESS) | V_SMB_TT_WR2BYTE, | ||
122 | SMB_CSR(R_SMB_START)); | ||
123 | |||
124 | while (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) | ||
125 | ; | ||
126 | |||
127 | if (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) { | ||
128 | /* Clear error bit by writing a 1 */ | ||
129 | bus_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS)); | ||
130 | return -1; | ||
131 | } | ||
132 | |||
133 | /* read the same byte again to make sure it is written */ | ||
134 | bus_writeq(V_SMB_ADDR(M41T81_CCR_ADDRESS) | V_SMB_TT_RD1BYTE, | ||
135 | SMB_CSR(R_SMB_START)); | ||
136 | |||
137 | while (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) | ||
138 | ; | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | int m41t81_set_time(unsigned long t) | ||
144 | { | ||
145 | struct rtc_time tm; | ||
146 | |||
147 | to_tm(t, &tm); | ||
148 | |||
149 | /* | ||
150 | * Note the write order matters as it ensures the correctness. | ||
151 | * When we write sec, 10th sec is clear. It is reasonable to | ||
152 | * believe we should finish writing min within a second. | ||
153 | */ | ||
154 | |||
155 | tm.tm_sec = BIN2BCD(tm.tm_sec); | ||
156 | m41t81_write(M41T81REG_SC, tm.tm_sec); | ||
157 | |||
158 | tm.tm_min = BIN2BCD(tm.tm_min); | ||
159 | m41t81_write(M41T81REG_MN, tm.tm_min); | ||
160 | |||
161 | tm.tm_hour = BIN2BCD(tm.tm_hour); | ||
162 | tm.tm_hour = (tm.tm_hour & 0x3f) | (m41t81_read(M41T81REG_HR) & 0xc0); | ||
163 | m41t81_write(M41T81REG_HR, tm.tm_hour); | ||
164 | |||
165 | /* tm_wday starts from 0 to 6 */ | ||
166 | if (tm.tm_wday == 0) tm.tm_wday = 7; | ||
167 | tm.tm_wday = BIN2BCD(tm.tm_wday); | ||
168 | m41t81_write(M41T81REG_DY, tm.tm_wday); | ||
169 | |||
170 | tm.tm_mday = BIN2BCD(tm.tm_mday); | ||
171 | m41t81_write(M41T81REG_DT, tm.tm_mday); | ||
172 | |||
173 | /* tm_mon starts from 0, *ick* */ | ||
174 | tm.tm_mon ++; | ||
175 | tm.tm_mon = BIN2BCD(tm.tm_mon); | ||
176 | m41t81_write(M41T81REG_MO, tm.tm_mon); | ||
177 | |||
178 | /* we don't do century, everything is beyond 2000 */ | ||
179 | tm.tm_year %= 100; | ||
180 | tm.tm_year = BIN2BCD(tm.tm_year); | ||
181 | m41t81_write(M41T81REG_YR, tm.tm_year); | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | unsigned long m41t81_get_time(void) | ||
187 | { | ||
188 | unsigned int year, mon, day, hour, min, sec; | ||
189 | |||
190 | /* | ||
191 | * min is valid if two reads of sec are the same. | ||
192 | */ | ||
193 | for (;;) { | ||
194 | sec = m41t81_read(M41T81REG_SC); | ||
195 | min = m41t81_read(M41T81REG_MN); | ||
196 | if (sec == m41t81_read(M41T81REG_SC)) break; | ||
197 | } | ||
198 | hour = m41t81_read(M41T81REG_HR) & 0x3f; | ||
199 | day = m41t81_read(M41T81REG_DT); | ||
200 | mon = m41t81_read(M41T81REG_MO); | ||
201 | year = m41t81_read(M41T81REG_YR); | ||
202 | |||
203 | sec = BCD2BIN(sec); | ||
204 | min = BCD2BIN(min); | ||
205 | hour = BCD2BIN(hour); | ||
206 | day = BCD2BIN(day); | ||
207 | mon = BCD2BIN(mon); | ||
208 | year = BCD2BIN(year); | ||
209 | |||
210 | year += 2000; | ||
211 | |||
212 | return mktime(year, mon, day, hour, min, sec); | ||
213 | } | ||
214 | |||
215 | int m41t81_probe(void) | ||
216 | { | ||
217 | unsigned int tmp; | ||
218 | |||
219 | /* enable chip if it is not enabled yet */ | ||
220 | tmp = m41t81_read(M41T81REG_SC); | ||
221 | m41t81_write(M41T81REG_SC, tmp & 0x7f); | ||
222 | |||
223 | return (m41t81_read(M41T81REG_SC) != -1); | ||
224 | } | ||
diff --git a/arch/mips/sibyte/swarm/rtc_xicor1241.c b/arch/mips/sibyte/swarm/rtc_xicor1241.c new file mode 100644 index 000000000000..981d21f16e64 --- /dev/null +++ b/arch/mips/sibyte/swarm/rtc_xicor1241.c | |||
@@ -0,0 +1,203 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000, 2001 Broadcom Corporation | ||
3 | * | ||
4 | * Copyright (C) 2002 MontaVista Software Inc. | ||
5 | * Author: jsun@mvista.com or jsun@junsun.net | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | #include <linux/bcd.h> | ||
13 | #include <linux/types.h> | ||
14 | #include <linux/time.h> | ||
15 | |||
16 | #include <asm/time.h> | ||
17 | #include <asm/addrspace.h> | ||
18 | #include <asm/io.h> | ||
19 | |||
20 | #include <asm/sibyte/sb1250.h> | ||
21 | #include <asm/sibyte/sb1250_regs.h> | ||
22 | #include <asm/sibyte/sb1250_smbus.h> | ||
23 | |||
24 | |||
25 | /* Xicor 1241 definitions */ | ||
26 | |||
27 | /* | ||
28 | * Register bits | ||
29 | */ | ||
30 | |||
31 | #define X1241REG_SR_BAT 0x80 /* currently on battery power */ | ||
32 | #define X1241REG_SR_RWEL 0x04 /* r/w latch is enabled, can write RTC */ | ||
33 | #define X1241REG_SR_WEL 0x02 /* r/w latch is unlocked, can enable r/w now */ | ||
34 | #define X1241REG_SR_RTCF 0x01 /* clock failed */ | ||
35 | #define X1241REG_BL_BP2 0x80 /* block protect 2 */ | ||
36 | #define X1241REG_BL_BP1 0x40 /* block protect 1 */ | ||
37 | #define X1241REG_BL_BP0 0x20 /* block protect 0 */ | ||
38 | #define X1241REG_BL_WD1 0x10 | ||
39 | #define X1241REG_BL_WD0 0x08 | ||
40 | #define X1241REG_HR_MIL 0x80 /* military time format */ | ||
41 | |||
42 | /* | ||
43 | * Register numbers | ||
44 | */ | ||
45 | |||
46 | #define X1241REG_BL 0x10 /* block protect bits */ | ||
47 | #define X1241REG_INT 0x11 /* */ | ||
48 | #define X1241REG_SC 0x30 /* Seconds */ | ||
49 | #define X1241REG_MN 0x31 /* Minutes */ | ||
50 | #define X1241REG_HR 0x32 /* Hours */ | ||
51 | #define X1241REG_DT 0x33 /* Day of month */ | ||
52 | #define X1241REG_MO 0x34 /* Month */ | ||
53 | #define X1241REG_YR 0x35 /* Year */ | ||
54 | #define X1241REG_DW 0x36 /* Day of Week */ | ||
55 | #define X1241REG_Y2K 0x37 /* Year 2K */ | ||
56 | #define X1241REG_SR 0x3F /* Status register */ | ||
57 | |||
58 | #define X1241_CCR_ADDRESS 0x6F | ||
59 | |||
60 | #define SMB_CSR(reg) ((u8 *) (IOADDR(A_SMB_REGISTER(1, reg)))) | ||
61 | |||
62 | static int xicor_read(uint8_t addr) | ||
63 | { | ||
64 | while (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) | ||
65 | ; | ||
66 | |||
67 | bus_writeq((addr >> 8) & 0x7, SMB_CSR(R_SMB_CMD)); | ||
68 | bus_writeq((addr & 0xff), SMB_CSR(R_SMB_DATA)); | ||
69 | bus_writeq((V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_WR2BYTE), | ||
70 | SMB_CSR(R_SMB_START)); | ||
71 | |||
72 | while (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) | ||
73 | ; | ||
74 | |||
75 | bus_writeq((V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_RD1BYTE), | ||
76 | SMB_CSR(R_SMB_START)); | ||
77 | |||
78 | while (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) | ||
79 | ; | ||
80 | |||
81 | if (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) { | ||
82 | /* Clear error bit by writing a 1 */ | ||
83 | bus_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS)); | ||
84 | return -1; | ||
85 | } | ||
86 | |||
87 | return (bus_readq(SMB_CSR(R_SMB_DATA)) & 0xff); | ||
88 | } | ||
89 | |||
90 | static int xicor_write(uint8_t addr, int b) | ||
91 | { | ||
92 | while (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) | ||
93 | ; | ||
94 | |||
95 | bus_writeq(addr, SMB_CSR(R_SMB_CMD)); | ||
96 | bus_writeq((addr & 0xff) | ((b & 0xff) << 8), SMB_CSR(R_SMB_DATA)); | ||
97 | bus_writeq(V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_WR3BYTE, | ||
98 | SMB_CSR(R_SMB_START)); | ||
99 | |||
100 | while (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) | ||
101 | ; | ||
102 | |||
103 | if (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) { | ||
104 | /* Clear error bit by writing a 1 */ | ||
105 | bus_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS)); | ||
106 | return -1; | ||
107 | } else { | ||
108 | return 0; | ||
109 | } | ||
110 | } | ||
111 | |||
112 | int xicor_set_time(unsigned long t) | ||
113 | { | ||
114 | struct rtc_time tm; | ||
115 | int tmp; | ||
116 | |||
117 | to_tm(t, &tm); | ||
118 | |||
119 | /* unlock writes to the CCR */ | ||
120 | xicor_write(X1241REG_SR, X1241REG_SR_WEL); | ||
121 | xicor_write(X1241REG_SR, X1241REG_SR_WEL | X1241REG_SR_RWEL); | ||
122 | |||
123 | /* trivial ones */ | ||
124 | tm.tm_sec = BIN2BCD(tm.tm_sec); | ||
125 | xicor_write(X1241REG_SC, tm.tm_sec); | ||
126 | |||
127 | tm.tm_min = BIN2BCD(tm.tm_min); | ||
128 | xicor_write(X1241REG_MN, tm.tm_min); | ||
129 | |||
130 | tm.tm_mday = BIN2BCD(tm.tm_mday); | ||
131 | xicor_write(X1241REG_DT, tm.tm_mday); | ||
132 | |||
133 | /* tm_mon starts from 0, *ick* */ | ||
134 | tm.tm_mon ++; | ||
135 | tm.tm_mon = BIN2BCD(tm.tm_mon); | ||
136 | xicor_write(X1241REG_MO, tm.tm_mon); | ||
137 | |||
138 | /* year is split */ | ||
139 | tmp = tm.tm_year / 100; | ||
140 | tm.tm_year %= 100; | ||
141 | xicor_write(X1241REG_YR, tm.tm_year); | ||
142 | xicor_write(X1241REG_Y2K, tmp); | ||
143 | |||
144 | /* hour is the most tricky one */ | ||
145 | tmp = xicor_read(X1241REG_HR); | ||
146 | if (tmp & X1241REG_HR_MIL) { | ||
147 | /* 24 hour format */ | ||
148 | tm.tm_hour = BIN2BCD(tm.tm_hour); | ||
149 | tmp = (tmp & ~0x3f) | (tm.tm_hour & 0x3f); | ||
150 | } else { | ||
151 | /* 12 hour format, with 0x2 for pm */ | ||
152 | tmp = tmp & ~0x3f; | ||
153 | if (tm.tm_hour >= 12) { | ||
154 | tmp |= 0x20; | ||
155 | tm.tm_hour -= 12; | ||
156 | } | ||
157 | tm.tm_hour = BIN2BCD(tm.tm_hour); | ||
158 | tmp |= tm.tm_hour; | ||
159 | } | ||
160 | xicor_write(X1241REG_HR, tmp); | ||
161 | |||
162 | xicor_write(X1241REG_SR, 0); | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | unsigned long xicor_get_time(void) | ||
168 | { | ||
169 | unsigned int year, mon, day, hour, min, sec, y2k; | ||
170 | |||
171 | sec = xicor_read(X1241REG_SC); | ||
172 | min = xicor_read(X1241REG_MN); | ||
173 | hour = xicor_read(X1241REG_HR); | ||
174 | |||
175 | if (hour & X1241REG_HR_MIL) { | ||
176 | hour &= 0x3f; | ||
177 | } else { | ||
178 | if (hour & 0x20) | ||
179 | hour = (hour & 0xf) + 0x12; | ||
180 | } | ||
181 | |||
182 | day = xicor_read(X1241REG_DT); | ||
183 | mon = xicor_read(X1241REG_MO); | ||
184 | year = xicor_read(X1241REG_YR); | ||
185 | y2k = xicor_read(X1241REG_Y2K); | ||
186 | |||
187 | sec = BCD2BIN(sec); | ||
188 | min = BCD2BIN(min); | ||
189 | hour = BCD2BIN(hour); | ||
190 | day = BCD2BIN(day); | ||
191 | mon = BCD2BIN(mon); | ||
192 | year = BCD2BIN(year); | ||
193 | y2k = BCD2BIN(y2k); | ||
194 | |||
195 | year += (y2k * 100); | ||
196 | |||
197 | return mktime(year, mon, day, hour, min, sec); | ||
198 | } | ||
199 | |||
200 | int xicor_probe(void) | ||
201 | { | ||
202 | return (xicor_read(X1241REG_SC) != -1); | ||
203 | } | ||
diff --git a/arch/mips/sibyte/swarm/setup.c b/arch/mips/sibyte/swarm/setup.c new file mode 100644 index 000000000000..457aeb7be858 --- /dev/null +++ b/arch/mips/sibyte/swarm/setup.c | |||
@@ -0,0 +1,163 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000, 2001, 2002, 2003 Broadcom Corporation | ||
3 | * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org) | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License | ||
7 | * as published by the Free Software Foundation; either version 2 | ||
8 | * of the License, or (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | /* | ||
21 | * Setup code for the SWARM board | ||
22 | */ | ||
23 | |||
24 | #include <linux/config.h> | ||
25 | #include <linux/spinlock.h> | ||
26 | #include <linux/mm.h> | ||
27 | #include <linux/bootmem.h> | ||
28 | #include <linux/blkdev.h> | ||
29 | #include <linux/init.h> | ||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/tty.h> | ||
32 | #include <linux/initrd.h> | ||
33 | |||
34 | #include <asm/irq.h> | ||
35 | #include <asm/io.h> | ||
36 | #include <asm/bootinfo.h> | ||
37 | #include <asm/mipsregs.h> | ||
38 | #include <asm/reboot.h> | ||
39 | #include <asm/time.h> | ||
40 | #include <asm/traps.h> | ||
41 | #include <asm/sibyte/sb1250.h> | ||
42 | #include <asm/sibyte/sb1250_regs.h> | ||
43 | #include <asm/sibyte/sb1250_genbus.h> | ||
44 | #include <asm/sibyte/board.h> | ||
45 | |||
46 | extern void sb1250_setup(void); | ||
47 | |||
48 | extern int xicor_probe(void); | ||
49 | extern int xicor_set_time(unsigned long); | ||
50 | extern unsigned long xicor_get_time(void); | ||
51 | |||
52 | extern int m41t81_probe(void); | ||
53 | extern int m41t81_set_time(unsigned long); | ||
54 | extern unsigned long m41t81_get_time(void); | ||
55 | |||
56 | const char *get_system_type(void) | ||
57 | { | ||
58 | return "SiByte " SIBYTE_BOARD_NAME; | ||
59 | } | ||
60 | |||
61 | void __init swarm_timer_setup(struct irqaction *irq) | ||
62 | { | ||
63 | /* | ||
64 | * we don't set up irqaction, because we will deliver timer | ||
65 | * interrupts through low-level (direct) meachanism. | ||
66 | */ | ||
67 | |||
68 | /* We only need to setup the generic timer */ | ||
69 | sb1250_time_init(); | ||
70 | } | ||
71 | |||
72 | int swarm_be_handler(struct pt_regs *regs, int is_fixup) | ||
73 | { | ||
74 | if (!is_fixup && (regs->cp0_cause & 4)) { | ||
75 | /* Data bus error - print PA */ | ||
76 | #ifdef CONFIG_MIPS64 | ||
77 | printk("DBE physical address: %010lx\n", | ||
78 | __read_64bit_c0_register($26, 1)); | ||
79 | #else | ||
80 | printk("DBE physical address: %010llx\n", | ||
81 | __read_64bit_c0_split($26, 1)); | ||
82 | #endif | ||
83 | } | ||
84 | return (is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL); | ||
85 | } | ||
86 | |||
87 | static int __init swarm_setup(void) | ||
88 | { | ||
89 | sb1250_setup(); | ||
90 | |||
91 | panic_timeout = 5; /* For debug. */ | ||
92 | |||
93 | board_timer_setup = swarm_timer_setup; | ||
94 | board_be_handler = swarm_be_handler; | ||
95 | |||
96 | if (xicor_probe()) { | ||
97 | printk("swarm setup: Xicor 1241 RTC detected.\n"); | ||
98 | rtc_get_time = xicor_get_time; | ||
99 | rtc_set_time = xicor_set_time; | ||
100 | } | ||
101 | |||
102 | if (m41t81_probe()) { | ||
103 | printk("swarm setup: M41T81 RTC detected.\n"); | ||
104 | rtc_get_time = m41t81_get_time; | ||
105 | rtc_set_time = m41t81_set_time; | ||
106 | } | ||
107 | |||
108 | printk("This kernel optimized for " | ||
109 | #ifdef CONFIG_SIMULATION | ||
110 | "simulation" | ||
111 | #else | ||
112 | "board" | ||
113 | #endif | ||
114 | " runs " | ||
115 | #ifdef CONFIG_SIBYTE_CFE | ||
116 | "with" | ||
117 | #else | ||
118 | "without" | ||
119 | #endif | ||
120 | " CFE\n"); | ||
121 | |||
122 | #ifdef CONFIG_VT | ||
123 | screen_info = (struct screen_info) { | ||
124 | 0, 0, /* orig-x, orig-y */ | ||
125 | 0, /* unused */ | ||
126 | 52, /* orig_video_page */ | ||
127 | 3, /* orig_video_mode */ | ||
128 | 80, /* orig_video_cols */ | ||
129 | 4626, 3, 9, /* unused, ega_bx, unused */ | ||
130 | 25, /* orig_video_lines */ | ||
131 | 0x22, /* orig_video_isVGA */ | ||
132 | 16 /* orig_video_points */ | ||
133 | }; | ||
134 | /* XXXKW for CFE, get lines/cols from environment */ | ||
135 | #endif | ||
136 | |||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | early_initcall(swarm_setup); | ||
141 | |||
142 | #ifdef LEDS_PHYS | ||
143 | |||
144 | #ifdef CONFIG_SIBYTE_CARMEL | ||
145 | /* XXXKW need to detect Monterey/LittleSur/etc */ | ||
146 | #undef LEDS_PHYS | ||
147 | #define LEDS_PHYS MLEDS_PHYS | ||
148 | #endif | ||
149 | |||
150 | #define setled(index, c) \ | ||
151 | ((unsigned char *)(IOADDR(LEDS_PHYS)+0x20))[(3-(index))<<3] = (c) | ||
152 | void setleds(char *str) | ||
153 | { | ||
154 | int i; | ||
155 | for (i = 0; i < 4; i++) { | ||
156 | if (!str[i]) { | ||
157 | setled(i, ' '); | ||
158 | } else { | ||
159 | setled(i, str[i]); | ||
160 | } | ||
161 | } | ||
162 | } | ||
163 | #endif | ||
diff --git a/arch/mips/sibyte/swarm/time.c b/arch/mips/sibyte/swarm/time.c new file mode 100644 index 000000000000..c1f1a9defeeb --- /dev/null +++ b/arch/mips/sibyte/swarm/time.c | |||
@@ -0,0 +1,244 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000, 2001 Broadcom Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version 2 | ||
7 | * of the License, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
17 | */ | ||
18 | |||
19 | /* | ||
20 | * Time routines for the swarm board. We pass all the hard stuff | ||
21 | * through to the sb1250 handling code. Only thing we really keep | ||
22 | * track of here is what time of day we think it is. And we don't | ||
23 | * really even do a good job of that... | ||
24 | */ | ||
25 | |||
26 | |||
27 | #include <linux/bcd.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/time.h> | ||
30 | #include <linux/sched.h> | ||
31 | #include <linux/spinlock.h> | ||
32 | #include <asm/system.h> | ||
33 | #include <asm/addrspace.h> | ||
34 | #include <asm/io.h> | ||
35 | |||
36 | #include <asm/sibyte/sb1250.h> | ||
37 | #include <asm/sibyte/sb1250_regs.h> | ||
38 | #include <asm/sibyte/sb1250_smbus.h> | ||
39 | |||
40 | static unsigned long long sec_bias = 0; | ||
41 | static unsigned int usec_bias = 0; | ||
42 | |||
43 | /* Xicor 1241 definitions */ | ||
44 | |||
45 | /* | ||
46 | * Register bits | ||
47 | */ | ||
48 | |||
49 | #define X1241REG_SR_BAT 0x80 /* currently on battery power */ | ||
50 | #define X1241REG_SR_RWEL 0x04 /* r/w latch is enabled, can write RTC */ | ||
51 | #define X1241REG_SR_WEL 0x02 /* r/w latch is unlocked, can enable r/w now */ | ||
52 | #define X1241REG_SR_RTCF 0x01 /* clock failed */ | ||
53 | #define X1241REG_BL_BP2 0x80 /* block protect 2 */ | ||
54 | #define X1241REG_BL_BP1 0x40 /* block protect 1 */ | ||
55 | #define X1241REG_BL_BP0 0x20 /* block protect 0 */ | ||
56 | #define X1241REG_BL_WD1 0x10 | ||
57 | #define X1241REG_BL_WD0 0x08 | ||
58 | #define X1241REG_HR_MIL 0x80 /* military time format */ | ||
59 | |||
60 | /* | ||
61 | * Register numbers | ||
62 | */ | ||
63 | |||
64 | #define X1241REG_BL 0x10 /* block protect bits */ | ||
65 | #define X1241REG_INT 0x11 /* */ | ||
66 | #define X1241REG_SC 0x30 /* Seconds */ | ||
67 | #define X1241REG_MN 0x31 /* Minutes */ | ||
68 | #define X1241REG_HR 0x32 /* Hours */ | ||
69 | #define X1241REG_DT 0x33 /* Day of month */ | ||
70 | #define X1241REG_MO 0x34 /* Month */ | ||
71 | #define X1241REG_YR 0x35 /* Year */ | ||
72 | #define X1241REG_DW 0x36 /* Day of Week */ | ||
73 | #define X1241REG_Y2K 0x37 /* Year 2K */ | ||
74 | #define X1241REG_SR 0x3F /* Status register */ | ||
75 | |||
76 | #define X1241_CCR_ADDRESS 0x6F | ||
77 | |||
78 | #define SMB_CSR(reg) (IOADDR(A_SMB_REGISTER(1, reg))) | ||
79 | |||
80 | static int xicor_read(uint8_t addr) | ||
81 | { | ||
82 | while (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) | ||
83 | ; | ||
84 | |||
85 | bus_writeq((addr >> 8) & 0x7, SMB_CSR(R_SMB_CMD)); | ||
86 | bus_writeq((addr & 0xff), SMB_CSR(R_SMB_DATA)); | ||
87 | bus_writeq((V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_WR2BYTE), | ||
88 | SMB_CSR(R_SMB_START)); | ||
89 | |||
90 | while (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) | ||
91 | ; | ||
92 | |||
93 | bus_writeq((V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_RD1BYTE), | ||
94 | SMB_CSR(R_SMB_START)); | ||
95 | |||
96 | while (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) | ||
97 | ; | ||
98 | |||
99 | if (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) { | ||
100 | /* Clear error bit by writing a 1 */ | ||
101 | bus_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS)); | ||
102 | return -1; | ||
103 | } | ||
104 | |||
105 | return (bus_readq(SMB_CSR(R_SMB_DATA)) & 0xff); | ||
106 | } | ||
107 | |||
108 | static int xicor_write(uint8_t addr, int b) | ||
109 | { | ||
110 | while (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) | ||
111 | ; | ||
112 | |||
113 | bus_writeq(addr, SMB_CSR(R_SMB_CMD)); | ||
114 | bus_writeq((addr & 0xff) | ((b & 0xff) << 8), SMB_CSR(R_SMB_DATA)); | ||
115 | bus_writeq(V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_WR3BYTE, | ||
116 | SMB_CSR(R_SMB_START)); | ||
117 | |||
118 | while (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) | ||
119 | ; | ||
120 | |||
121 | if (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) { | ||
122 | /* Clear error bit by writing a 1 */ | ||
123 | bus_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS)); | ||
124 | return -1; | ||
125 | } else { | ||
126 | return 0; | ||
127 | } | ||
128 | } | ||
129 | |||
130 | /* | ||
131 | * In order to set the CMOS clock precisely, set_rtc_mmss has to be | ||
132 | * called 500 ms after the second nowtime has started, because when | ||
133 | * nowtime is written into the registers of the CMOS clock, it will | ||
134 | * jump to the next second precisely 500 ms later. Check the Motorola | ||
135 | * MC146818A or Dallas DS12887 data sheet for details. | ||
136 | * | ||
137 | * BUG: This routine does not handle hour overflow properly; it just | ||
138 | * sets the minutes. Usually you'll only notice that after reboot! | ||
139 | */ | ||
140 | int set_rtc_mmss(unsigned long nowtime) | ||
141 | { | ||
142 | int retval = 0; | ||
143 | int real_seconds, real_minutes, cmos_minutes; | ||
144 | |||
145 | cmos_minutes = xicor_read(X1241REG_MN); | ||
146 | cmos_minutes = BCD2BIN(cmos_minutes); | ||
147 | |||
148 | /* | ||
149 | * since we're only adjusting minutes and seconds, | ||
150 | * don't interfere with hour overflow. This avoids | ||
151 | * messing with unknown time zones but requires your | ||
152 | * RTC not to be off by more than 15 minutes | ||
153 | */ | ||
154 | real_seconds = nowtime % 60; | ||
155 | real_minutes = nowtime / 60; | ||
156 | if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) | ||
157 | real_minutes += 30; /* correct for half hour time zone */ | ||
158 | real_minutes %= 60; | ||
159 | |||
160 | /* unlock writes to the CCR */ | ||
161 | xicor_write(X1241REG_SR, X1241REG_SR_WEL); | ||
162 | xicor_write(X1241REG_SR, X1241REG_SR_WEL | X1241REG_SR_RWEL); | ||
163 | |||
164 | if (abs(real_minutes - cmos_minutes) < 30) { | ||
165 | real_seconds = BIN2BCD(real_seconds); | ||
166 | real_minutes = BIN2BCD(real_minutes); | ||
167 | xicor_write(X1241REG_SC, real_seconds); | ||
168 | xicor_write(X1241REG_MN, real_minutes); | ||
169 | } else { | ||
170 | printk(KERN_WARNING | ||
171 | "set_rtc_mmss: can't update from %d to %d\n", | ||
172 | cmos_minutes, real_minutes); | ||
173 | retval = -1; | ||
174 | } | ||
175 | |||
176 | xicor_write(X1241REG_SR, 0); | ||
177 | |||
178 | printk("set_rtc_mmss: %02d:%02d\n", real_minutes, real_seconds); | ||
179 | |||
180 | return retval; | ||
181 | } | ||
182 | |||
183 | static unsigned long __init get_swarm_time(void) | ||
184 | { | ||
185 | unsigned int year, mon, day, hour, min, sec, y2k; | ||
186 | |||
187 | sec = xicor_read(X1241REG_SC); | ||
188 | min = xicor_read(X1241REG_MN); | ||
189 | hour = xicor_read(X1241REG_HR); | ||
190 | |||
191 | if (hour & X1241REG_HR_MIL) { | ||
192 | hour &= 0x3f; | ||
193 | } else { | ||
194 | if (hour & 0x20) | ||
195 | hour = (hour & 0xf) + 0x12; | ||
196 | } | ||
197 | |||
198 | sec = BCD2BIN(sec); | ||
199 | min = BCD2BIN(min); | ||
200 | hour = BCD2BIN(hour); | ||
201 | |||
202 | day = xicor_read(X1241REG_DT); | ||
203 | mon = xicor_read(X1241REG_MO); | ||
204 | year = xicor_read(X1241REG_YR); | ||
205 | y2k = xicor_read(X1241REG_Y2K); | ||
206 | |||
207 | day = BCD2BIN(day); | ||
208 | mon = BCD2BIN(mon); | ||
209 | year = BCD2BIN(year); | ||
210 | y2k = BCD2BIN(y2k); | ||
211 | |||
212 | year += (y2k * 100); | ||
213 | |||
214 | return mktime(year, mon, day, hour, min, sec); | ||
215 | } | ||
216 | |||
217 | /* | ||
218 | * Bring up the timer at 100 Hz. | ||
219 | */ | ||
220 | void __init swarm_time_init(void) | ||
221 | { | ||
222 | unsigned int flags; | ||
223 | int status; | ||
224 | |||
225 | /* Set up the scd general purpose timer 0 to cpu 0 */ | ||
226 | sb1250_time_init(); | ||
227 | |||
228 | /* Establish communication with the Xicor 1241 RTC */ | ||
229 | /* XXXKW how do I share the SMBus with the I2C subsystem? */ | ||
230 | |||
231 | bus_writeq(K_SMB_FREQ_400KHZ, SMB_CSR(R_SMB_FREQ)); | ||
232 | bus_writeq(0, SMB_CSR(R_SMB_CONTROL)); | ||
233 | |||
234 | if ((status = xicor_read(X1241REG_SR_RTCF)) < 0) { | ||
235 | printk("x1241: couldn't detect on SWARM SMBus 1\n"); | ||
236 | } else { | ||
237 | if (status & X1241REG_SR_RTCF) | ||
238 | printk("x1241: battery failed -- time is probably wrong\n"); | ||
239 | write_seqlock_irqsave(&xtime_lock, flags); | ||
240 | xtime.tv_sec = get_swarm_time(); | ||
241 | xtime.tv_nsec = 0; | ||
242 | write_sequnlock_irqrestore(&xtime_lock, flags); | ||
243 | } | ||
244 | } | ||