| @@ -1,217 +1,224 @@ | | | @@ -1,217 +1,224 @@ |
1 | /* $NetBSD: mfp.c,v 1.20 2008/12/18 02:27:41 isaki Exp $ */ | | 1 | /* $NetBSD: mfp.c,v 1.21 2008/12/31 08:00:31 isaki Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1998 NetBSD Foundation, Inc. | | 4 | * Copyright (c) 1998 NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
15 | * 3. All advertising materials mentioning features or use of this software | | 15 | * 3. All advertising materials mentioning features or use of this software |
16 | * must display the following acknowledgement: | | 16 | * must display the following acknowledgement: |
17 | * This product includes software developed by the NetBSD | | 17 | * This product includes software developed by the NetBSD |
18 | * Foundation, Inc. and its contributors. | | 18 | * Foundation, Inc. and its contributors. |
19 | * 4. The name of the author may not be used to endorse or promote products | | 19 | * 4. The name of the author may not be used to endorse or promote products |
20 | * derived from this software without specific prior written permission. | | 20 | * derived from this software without specific prior written permission. |
21 | * | | 21 | * |
22 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 22 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
23 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 23 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
24 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 24 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
25 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 25 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
26 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 26 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
32 | * POSSIBILITY OF SUCH DAMAGE. | | 32 | * POSSIBILITY OF SUCH DAMAGE. |
33 | */ | | 33 | */ |
34 | | | 34 | |
35 | /* | | 35 | /* |
36 | * MC68901 MFP (multi function periferal) driver for NetBSD/x68k | | 36 | * MC68901 MFP (multi function periferal) driver for NetBSD/x68k |
37 | */ | | 37 | */ |
38 | | | 38 | |
39 | /* | | 39 | /* |
40 | * MFP is used as keyboard controller, which may be used before | | 40 | * MFP is used as keyboard controller, which may be used before |
41 | * ordinary initialization. | | 41 | * ordinary initialization. |
42 | */ | | 42 | */ |
43 | | | 43 | |
44 | #include <sys/cdefs.h> | | 44 | #include <sys/cdefs.h> |
45 | __KERNEL_RCSID(0, "$NetBSD: mfp.c,v 1.20 2008/12/18 02:27:41 isaki Exp $"); | | 45 | __KERNEL_RCSID(0, "$NetBSD: mfp.c,v 1.21 2008/12/31 08:00:31 isaki Exp $"); |
46 | | | 46 | |
47 | #include <sys/param.h> | | 47 | #include <sys/param.h> |
48 | #include <sys/systm.h> | | 48 | #include <sys/systm.h> |
49 | #include <sys/device.h> | | 49 | #include <sys/device.h> |
50 | #include <sys/malloc.h> | | 50 | #include <sys/malloc.h> |
51 | | | 51 | |
52 | #include <machine/bus.h> | | 52 | #include <machine/bus.h> |
53 | #include <machine/cpu.h> | | 53 | #include <machine/cpu.h> |
54 | | | 54 | |
55 | #include <arch/x68k/dev/intiovar.h> | | 55 | #include <arch/x68k/dev/intiovar.h> |
56 | #include <arch/x68k/dev/mfp.h> | | 56 | #include <arch/x68k/dev/mfp.h> |
57 | | | 57 | |
58 | static int mfp_match(struct device *, struct cfdata *, void *); | | 58 | static int mfp_match(struct device *, struct cfdata *, void *); |
59 | static void mfp_attach(struct device *, struct device *, void *); | | 59 | static void mfp_attach(struct device *, struct device *, void *); |
| | | 60 | static int mfp_search(device_t, cfdata_t, const int *, void *); |
60 | static void mfp_init(void); | | 61 | static void mfp_init(void); |
61 | static void mfp_calibrate_delay(void); | | 62 | static void mfp_calibrate_delay(void); |
62 | | | 63 | |
63 | CFATTACH_DECL(mfp, sizeof(struct mfp_softc), | | 64 | CFATTACH_DECL(mfp, sizeof(struct mfp_softc), |
64 | mfp_match, mfp_attach, NULL, NULL); | | 65 | mfp_match, mfp_attach, NULL, NULL); |
65 | | | 66 | |
66 | static int mfp_attached; | | 67 | static int mfp_attached; |
67 | | | 68 | |
68 | static int | | 69 | static int |
69 | mfp_match(struct device *parent, struct cfdata *cf, void *aux) | | 70 | mfp_match(struct device *parent, struct cfdata *cf, void *aux) |
70 | { | | 71 | { |
71 | struct intio_attach_args *ia = aux; | | 72 | struct intio_attach_args *ia = aux; |
72 | | | 73 | |
73 | /* mfp0 */ | | 74 | /* mfp0 */ |
74 | if (strcmp(ia->ia_name, "mfp") != 0) | | 75 | if (strcmp(ia->ia_name, "mfp") != 0) |
75 | return 0; | | 76 | return 0; |
76 | if (mfp_attached) | | 77 | if (mfp_attached) |
77 | return (0); | | 78 | return (0); |
78 | | | 79 | |
79 | if (ia->ia_addr == INTIOCF_ADDR_DEFAULT) | | 80 | if (ia->ia_addr == INTIOCF_ADDR_DEFAULT) |
80 | ia->ia_addr = MFP_ADDR; | | 81 | ia->ia_addr = MFP_ADDR; |
81 | if (ia->ia_intr == INTIOCF_INTR_DEFAULT) | | 82 | if (ia->ia_intr == INTIOCF_INTR_DEFAULT) |
82 | ia->ia_addr = MFP_INTR; | | 83 | ia->ia_addr = MFP_INTR; |
83 | | | 84 | |
84 | /* fixed address */ | | 85 | /* fixed address */ |
85 | if (ia->ia_addr != MFP_ADDR) | | 86 | if (ia->ia_addr != MFP_ADDR) |
86 | return (0); | | 87 | return (0); |
87 | if (ia->ia_intr != MFP_INTR) | | 88 | if (ia->ia_intr != MFP_INTR) |
88 | return (0); | | 89 | return (0); |
89 | | | 90 | |
90 | return (1); | | 91 | return (1); |
91 | } | | 92 | } |
92 | | | 93 | |
93 | | | 94 | |
94 | static void | | 95 | static void |
95 | mfp_attach(struct device *parent, struct device *self, void *aux) | | 96 | mfp_attach(struct device *parent, struct device *self, void *aux) |
96 | { | | 97 | { |
97 | struct mfp_softc *sc = (struct mfp_softc *)self; | | 98 | struct mfp_softc *sc = (struct mfp_softc *)self; |
98 | struct intio_attach_args *ia = aux; | | 99 | struct intio_attach_args *ia = aux; |
99 | | | 100 | |
100 | mfp_init(); | | 101 | mfp_init(); |
101 | | | 102 | |
102 | if (sc != NULL) { | | 103 | if (sc != NULL) { |
103 | /* realconfig */ | | 104 | /* realconfig */ |
104 | int r; | | 105 | int r; |
105 | | | 106 | |
106 | printf("\n"); | | 107 | printf("\n"); |
107 | | | 108 | |
108 | mfp_attached = 1; | | 109 | mfp_attached = 1; |
109 | sc->sc_bst = ia->ia_bst; | | 110 | sc->sc_bst = ia->ia_bst; |
110 | sc->sc_intr = ia->ia_intr; | | 111 | sc->sc_intr = ia->ia_intr; |
111 | ia->ia_size = 0x30; | | 112 | ia->ia_size = 0x30; |
112 | r = intio_map_allocate_region(parent, ia, INTIO_MAP_ALLOCATE); | | 113 | r = intio_map_allocate_region(parent, ia, INTIO_MAP_ALLOCATE); |
113 | #ifdef DIAGNOSTIC | | 114 | #ifdef DIAGNOSTIC |
114 | if (r) | | 115 | if (r) |
115 | panic("IO map for MFP corruption??"); | | 116 | panic("IO map for MFP corruption??"); |
116 | #endif | | 117 | #endif |
117 | bus_space_map(ia->ia_bst, ia->ia_addr, 0x2000, 0, &sc->sc_bht); | | 118 | bus_space_map(ia->ia_bst, ia->ia_addr, 0x2000, 0, &sc->sc_bht); |
118 | config_found(self, __UNCONST("kbd"), NULL); | | 119 | config_search_ia(mfp_search, self, "mfp", NULL); |
119 | config_found(self, __UNCONST("clock"), NULL); | | | |
120 | config_found(self, __UNCONST("pow"), NULL); | | | |
121 | } else { | | 120 | } else { |
122 | /* | | 121 | /* |
123 | * Called from config_console; | | 122 | * Called from config_console; |
124 | * calibrate the DELAY loop counter | | 123 | * calibrate the DELAY loop counter |
125 | */ | | 124 | */ |
126 | mfp_calibrate_delay(); | | 125 | mfp_calibrate_delay(); |
127 | } | | 126 | } |
128 | } | | 127 | } |
129 | | | 128 | |
| | | 129 | static int |
| | | 130 | mfp_search(device_t parent, cfdata_t cf, const int *loc, void *aux) |
| | | 131 | { |
| | | 132 | if (config_match(parent, cf, __UNCONST(cf->cf_name)) > 0) |
| | | 133 | config_attach(parent, cf, __UNCONST(cf->cf_name), NULL); |
| | | 134 | return 0; |
| | | 135 | } |
| | | 136 | |
130 | static void | | 137 | static void |
131 | mfp_init(void) | | 138 | mfp_init(void) |
132 | { | | 139 | { |
133 | mfp_set_vr(MFP_INTR); | | 140 | mfp_set_vr(MFP_INTR); |
134 | | | 141 | |
135 | /* stop all interrupts */ | | 142 | /* stop all interrupts */ |
136 | mfp_set_iera(0); | | 143 | mfp_set_iera(0); |
137 | mfp_set_ierb(0); | | 144 | mfp_set_ierb(0); |
138 | | | 145 | |
139 | /* make MSCTRL 'High', XXX where should I do it? */ | | 146 | /* make MSCTRL 'High', XXX where should I do it? */ |
140 | mfp_send_usart(0x41); | | 147 | mfp_send_usart(0x41); |
141 | | | 148 | |
142 | /* Timer A settings */ | | 149 | /* Timer A settings */ |
143 | mfp_set_tacr(MFP_TIMERA_RESET | MFP_TIMERA_STOP); | | 150 | mfp_set_tacr(MFP_TIMERA_RESET | MFP_TIMERA_STOP); |
144 | | | 151 | |
145 | /* Timer B settings: used for USART clock */ | | 152 | /* Timer B settings: used for USART clock */ |
146 | mfp_set_tbcr(MFP_TIMERB_RESET | MFP_TIMERB_STOP); | | 153 | mfp_set_tbcr(MFP_TIMERB_RESET | MFP_TIMERB_STOP); |
147 | | | 154 | |
148 | /* Timer C/D settings */ | | 155 | /* Timer C/D settings */ |
149 | mfp_set_tcdcr(0); | | 156 | mfp_set_tcdcr(0); |
150 | } | | 157 | } |
151 | | | 158 | |
152 | extern int delay_divisor; | | 159 | extern int delay_divisor; |
153 | void _delay(u_int); | | 160 | void _delay(u_int); |
154 | | | 161 | |
155 | static void | | 162 | static void |
156 | mfp_calibrate_delay(void) | | 163 | mfp_calibrate_delay(void) |
157 | { | | 164 | { |
158 | /* | | 165 | /* |
159 | * Stolen from mvme68k. | | 166 | * Stolen from mvme68k. |
160 | */ | | 167 | */ |
161 | /* | | 168 | /* |
162 | * X68k provides 4MHz clock (= 0.25usec) for MFP timer C. | | 169 | * X68k provides 4MHz clock (= 0.25usec) for MFP timer C. |
163 | * 10000usec = 0.25usec * 200 * 200 | | 170 | * 10000usec = 0.25usec * 200 * 200 |
164 | * Our slowest clock is 20MHz (?). Its delay_divisor value | | 171 | * Our slowest clock is 20MHz (?). Its delay_divisor value |
165 | * should be about 102. Start from 140 here. | | 172 | * should be about 102. Start from 140 here. |
166 | */ | | 173 | */ |
167 | for (delay_divisor = 140; delay_divisor > 0; delay_divisor--) { | | 174 | for (delay_divisor = 140; delay_divisor > 0; delay_divisor--) { |
168 | mfp_set_tcdr(255-0); | | 175 | mfp_set_tcdr(255-0); |
169 | mfp_set_tcdcr(0x70); /* 1/200 delay mode */ | | 176 | mfp_set_tcdcr(0x70); /* 1/200 delay mode */ |
170 | _delay(10000 << 8); | | 177 | _delay(10000 << 8); |
171 | mfp_set_tcdcr(0); /* stop timer */ | | 178 | mfp_set_tcdcr(0); /* stop timer */ |
172 | if ((255 - mfp_get_tcdr()) > 200) | | 179 | if ((255 - mfp_get_tcdr()) > 200) |
173 | break; /* got it! */ | | 180 | break; /* got it! */ |
174 | /* retry! */ | | 181 | /* retry! */ |
175 | } | | 182 | } |
176 | } | | 183 | } |
177 | | | 184 | |
178 | /* | | 185 | /* |
179 | * MFP utility functions | | 186 | * MFP utility functions |
180 | */ | | 187 | */ |
181 | | | 188 | |
182 | /* | | 189 | /* |
183 | * wait for built-in display hsync. | | 190 | * wait for built-in display hsync. |
184 | * should be called before writing to frame buffer. | | 191 | * should be called before writing to frame buffer. |
185 | * might be called before realconfig. | | 192 | * might be called before realconfig. |
186 | */ | | 193 | */ |
187 | void | | 194 | void |
188 | mfp_wait_for_hsync(void) | | 195 | mfp_wait_for_hsync(void) |
189 | { | | 196 | { |
190 | /* wait for CRT HSYNC */ | | 197 | /* wait for CRT HSYNC */ |
191 | while (mfp_get_gpip() & MFP_GPIP_HSYNC) | | 198 | while (mfp_get_gpip() & MFP_GPIP_HSYNC) |
192 | __asm("nop"); | | 199 | __asm("nop"); |
193 | while (!(mfp_get_gpip() & MFP_GPIP_HSYNC)) | | 200 | while (!(mfp_get_gpip() & MFP_GPIP_HSYNC)) |
194 | __asm("nop"); | | 201 | __asm("nop"); |
195 | } | | 202 | } |
196 | | | 203 | |
197 | /* | | 204 | /* |
198 | * send COMMAND to the MFP USART. | | 205 | * send COMMAND to the MFP USART. |
199 | * USART is attached to the keyboard. | | 206 | * USART is attached to the keyboard. |
200 | * might be called before realconfig. | | 207 | * might be called before realconfig. |
201 | */ | | 208 | */ |
202 | int | | 209 | int |
203 | mfp_send_usart(int command) | | 210 | mfp_send_usart(int command) |
204 | { | | 211 | { |
205 | while (!(mfp_get_tsr() & MFP_TSR_BE)); | | 212 | while (!(mfp_get_tsr() & MFP_TSR_BE)); |
206 | mfp_set_udr(command); | | 213 | mfp_set_udr(command); |
207 | | | 214 | |
208 | return 0; | | 215 | return 0; |
209 | } | | 216 | } |
210 | | | 217 | |
211 | int | | 218 | int |
212 | mfp_receive_usart(void) | | 219 | mfp_receive_usart(void) |
213 | { | | 220 | { |
214 | while (!(mfp_get_rsr() & MFP_RSR_BF)) | | 221 | while (!(mfp_get_rsr() & MFP_RSR_BF)) |
215 | __asm("nop"); | | 222 | __asm("nop"); |
216 | return mfp_get_udr(); | | 223 | return mfp_get_udr(); |
217 | } | | 224 | } |