spd.c revision 1.9.6.3 1 1.9.6.2 tls /* $NetBSD: spd.c,v 1.9.6.3 2017/12/03 11:36:35 jdolecek Exp $ */
2 1.9.6.2 tls
3 1.9.6.2 tls /*-
4 1.9.6.2 tls * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 1.9.6.2 tls * All rights reserved.
6 1.9.6.2 tls *
7 1.9.6.2 tls * This code is derived from software contributed to The NetBSD Foundation
8 1.9.6.2 tls * by UCHIYAMA Yasushi.
9 1.9.6.2 tls *
10 1.9.6.2 tls * Redistribution and use in source and binary forms, with or without
11 1.9.6.2 tls * modification, are permitted provided that the following conditions
12 1.9.6.2 tls * are met:
13 1.9.6.2 tls * 1. Redistributions of source code must retain the above copyright
14 1.9.6.2 tls * notice, this list of conditions and the following disclaimer.
15 1.9.6.2 tls * 2. Redistributions in binary form must reproduce the above copyright
16 1.9.6.2 tls * notice, this list of conditions and the following disclaimer in the
17 1.9.6.2 tls * documentation and/or other materials provided with the distribution.
18 1.9.6.2 tls *
19 1.9.6.2 tls * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.9.6.2 tls * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.9.6.2 tls * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.9.6.2 tls * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.9.6.2 tls * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.9.6.2 tls * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.9.6.2 tls * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.9.6.2 tls * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.9.6.2 tls * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.9.6.2 tls * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.9.6.2 tls * POSSIBILITY OF SUCH DAMAGE.
30 1.9.6.2 tls */
31 1.9.6.2 tls
32 1.9.6.2 tls #include <sys/cdefs.h>
33 1.9.6.2 tls __KERNEL_RCSID(0, "$NetBSD: spd.c,v 1.9.6.3 2017/12/03 11:36:35 jdolecek Exp $");
34 1.9.6.2 tls
35 1.9.6.2 tls #include <sys/param.h>
36 1.9.6.3 jdolecek #include <sys/device.h>
37 1.9.6.2 tls #include <sys/systm.h>
38 1.9.6.2 tls
39 1.9.6.2 tls #include <machine/bootinfo.h>
40 1.9.6.2 tls
41 1.9.6.2 tls #include <playstation2/ee/eevar.h>
42 1.9.6.2 tls #include <playstation2/dev/sbusvar.h>
43 1.9.6.2 tls #include <playstation2/dev/spdvar.h>
44 1.9.6.2 tls #include <playstation2/dev/spdreg.h>
45 1.9.6.2 tls
46 1.9.6.2 tls #ifdef DEBUG
47 1.9.6.2 tls #define STATIC
48 1.9.6.2 tls #else
49 1.9.6.2 tls #define STATIC static
50 1.9.6.2 tls #endif
51 1.9.6.2 tls
52 1.9.6.3 jdolecek STATIC int spd_match(device_t, cfdata_t, void *);
53 1.9.6.3 jdolecek STATIC void spd_attach(device_t, device_t, void *);
54 1.9.6.2 tls STATIC int spd_print(void *, const char *);
55 1.9.6.2 tls STATIC int spd_intr(void *);
56 1.9.6.2 tls STATIC void __spd_eeprom_out(u_int8_t *, int);
57 1.9.6.2 tls STATIC int __spd_eeprom_in(u_int8_t *);
58 1.9.6.2 tls
59 1.9.6.2 tls /* SPD device can't attach twice. because PS2 PC-Card slot is only one. */
60 1.9.6.2 tls STATIC struct {
61 1.9.6.2 tls int (*func)(void *);
62 1.9.6.2 tls void *arg;
63 1.9.6.2 tls const char *name;
64 1.9.6.2 tls } __spd_table[2];
65 1.9.6.2 tls
66 1.9.6.3 jdolecek CFATTACH_DECL_NEW(spd, sizeof(struct device),
67 1.9.6.2 tls spd_match, spd_attach, NULL, NULL);
68 1.9.6.2 tls
69 1.9.6.2 tls #ifdef DEBUG
70 1.9.6.2 tls #define LEGAL_SLOT(slot) ((slot) >= 0 && (slot) < 2)
71 1.9.6.2 tls #endif
72 1.9.6.2 tls
73 1.9.6.2 tls int
74 1.9.6.3 jdolecek spd_match(device_t parent, cfdata_t cf, void *aux)
75 1.9.6.2 tls {
76 1.9.6.2 tls
77 1.9.6.2 tls return ((BOOTINFO_REF(BOOTINFO_DEVCONF) ==
78 1.9.6.2 tls BOOTINFO_DEVCONF_SPD_PRESENT));
79 1.9.6.2 tls }
80 1.9.6.2 tls
81 1.9.6.2 tls void
82 1.9.6.3 jdolecek spd_attach(device_t parent, device_t self, void *aux)
83 1.9.6.2 tls {
84 1.9.6.2 tls struct spd_attach_args spa;
85 1.9.6.2 tls
86 1.9.6.2 tls printf(": PlayStation 2 HDD Unit\n");
87 1.9.6.2 tls
88 1.9.6.2 tls switch (BOOTINFO_REF(BOOTINFO_PCMCIA_TYPE)) {
89 1.9.6.2 tls default:
90 1.9.6.2 tls __spd_table[0].name = "<unknown product>";
91 1.9.6.2 tls break;
92 1.9.6.2 tls case 0:
93 1.9.6.2 tls /* FALLTHROUGH */
94 1.9.6.2 tls case 1:
95 1.9.6.2 tls /* FALLTHROUGH */
96 1.9.6.2 tls case 2:
97 1.9.6.2 tls __spd_table[SPD_HDD].name = "SCPH-20400";
98 1.9.6.2 tls __spd_table[SPD_NIC].name = "SCPH-10190";
99 1.9.6.2 tls break;
100 1.9.6.2 tls case 3:
101 1.9.6.2 tls __spd_table[SPD_HDD].name = "SCPH-10260";
102 1.9.6.2 tls __spd_table[SPD_NIC].name = "SCPH-10260";
103 1.9.6.2 tls break;
104 1.9.6.2 tls }
105 1.9.6.2 tls
106 1.9.6.2 tls /* disable all */
107 1.9.6.2 tls _reg_write_2(SPD_INTR_ENABLE_REG16, 0);
108 1.9.6.2 tls _reg_write_2(SPD_INTR_CLEAR_REG16, _reg_read_2(SPD_INTR_STATUS_REG16));
109 1.9.6.2 tls
110 1.9.6.2 tls spa.spa_slot = SPD_HDD;
111 1.9.6.2 tls spa.spa_product_name = __spd_table[SPD_HDD].name;
112 1.9.6.2 tls config_found(self, &spa, spd_print);
113 1.9.6.2 tls
114 1.9.6.2 tls spa.spa_slot = SPD_NIC;
115 1.9.6.2 tls spa.spa_product_name = __spd_table[SPD_NIC].name;
116 1.9.6.2 tls config_found(self, &spa, spd_print);
117 1.9.6.2 tls
118 1.9.6.2 tls sbus_intr_establish(SBUS_IRQ_PCMCIA, spd_intr, 0);
119 1.9.6.2 tls }
120 1.9.6.2 tls
121 1.9.6.2 tls int
122 1.9.6.2 tls spd_print(void *aux, const char *pnp)
123 1.9.6.2 tls {
124 1.9.6.2 tls struct spd_attach_args *spa = aux;
125 1.9.6.2 tls
126 1.9.6.2 tls if (pnp)
127 1.9.6.2 tls aprint_normal("%s at %s", __spd_table[spa->spa_slot].name, pnp);
128 1.9.6.2 tls
129 1.9.6.2 tls return (UNCONF);
130 1.9.6.2 tls }
131 1.9.6.2 tls
132 1.9.6.2 tls int
133 1.9.6.2 tls spd_intr(void *arg)
134 1.9.6.2 tls {
135 1.9.6.2 tls u_int16_t r;
136 1.9.6.2 tls
137 1.9.6.2 tls r = _reg_read_2(SPD_INTR_STATUS_REG16);
138 1.9.6.2 tls
139 1.9.6.2 tls /* HDD (SCPH-20400) */
140 1.9.6.2 tls if ((r & SPD_INTR_HDD) != 0)
141 1.9.6.2 tls if (__spd_table[SPD_HDD].func != NULL)
142 1.9.6.2 tls (*__spd_table[SPD_HDD].func)(__spd_table[SPD_HDD].arg);
143 1.9.6.2 tls
144 1.9.6.2 tls /* Network (SCPH-10190) */
145 1.9.6.2 tls if ((r & (SPD_INTR_EMAC3 | SPD_INTR_RXEND | SPD_INTR_TXEND |
146 1.9.6.2 tls SPD_INTR_RXDNV | SPD_INTR_TXDNV)) != 0)
147 1.9.6.2 tls if (__spd_table[SPD_NIC].func)
148 1.9.6.2 tls (*__spd_table[SPD_NIC].func)(__spd_table[SPD_NIC].arg);
149 1.9.6.2 tls
150 1.9.6.2 tls /* reinstall */
151 1.9.6.2 tls r = _reg_read_2(SPD_INTR_ENABLE_REG16);
152 1.9.6.2 tls _reg_write_2(SPD_INTR_ENABLE_REG16, 0);
153 1.9.6.2 tls _reg_write_2(SPD_INTR_ENABLE_REG16, r);
154 1.9.6.2 tls
155 1.9.6.2 tls return (1);
156 1.9.6.2 tls }
157 1.9.6.2 tls
158 1.9.6.2 tls void *
159 1.9.6.2 tls spd_intr_establish(enum spd_slot slot, int (*func)(void *), void *arg)
160 1.9.6.2 tls {
161 1.9.6.2 tls
162 1.9.6.2 tls KDASSERT(LEGAL_SLOT(slot));
163 1.9.6.2 tls KDASSERT(__spd_table[slot].func == 0);
164 1.9.6.2 tls
165 1.9.6.2 tls __spd_table[slot].func = func;
166 1.9.6.2 tls __spd_table[slot].arg = arg;
167 1.9.6.2 tls
168 1.9.6.2 tls return ((void *)slot);
169 1.9.6.2 tls }
170 1.9.6.2 tls
171 1.9.6.2 tls void
172 1.9.6.2 tls spd_intr_disestablish(void *handle)
173 1.9.6.2 tls {
174 1.9.6.2 tls int slot = (int)handle;
175 1.9.6.2 tls
176 1.9.6.2 tls KDASSERT(LEGAL_SLOT(slot));
177 1.9.6.2 tls
178 1.9.6.2 tls __spd_table[slot].func = 0;
179 1.9.6.2 tls }
180 1.9.6.2 tls
181 1.9.6.2 tls /*
182 1.9.6.2 tls * EEPROM access
183 1.9.6.2 tls */
184 1.9.6.2 tls void
185 1.9.6.2 tls spd_eeprom_read(int addr, u_int16_t *data, int n)
186 1.9.6.2 tls {
187 1.9.6.2 tls int i, j, s;
188 1.9.6.2 tls u_int8_t r;
189 1.9.6.2 tls
190 1.9.6.2 tls s = _intr_suspend();
191 1.9.6.2 tls
192 1.9.6.2 tls /* set direction */
193 1.9.6.2 tls _reg_write_1(SPD_IO_DIR_REG8, SPD_IO_CLK | SPD_IO_CS | SPD_IO_IN);
194 1.9.6.2 tls
195 1.9.6.2 tls /* chip select high */
196 1.9.6.2 tls r = 0;
197 1.9.6.2 tls _reg_write_1(SPD_IO_DATA_REG8, r);
198 1.9.6.2 tls delay(1);
199 1.9.6.2 tls r |= SPD_IO_CS;
200 1.9.6.2 tls r &= ~(SPD_IO_IN | SPD_IO_CLK);
201 1.9.6.2 tls _reg_write_1(SPD_IO_DATA_REG8, r);
202 1.9.6.2 tls delay(1);
203 1.9.6.2 tls
204 1.9.6.2 tls /* put start bit */
205 1.9.6.2 tls __spd_eeprom_out(&r, 1);
206 1.9.6.2 tls
207 1.9.6.2 tls /* put op code (read) */
208 1.9.6.2 tls __spd_eeprom_out(&r, 1);
209 1.9.6.2 tls __spd_eeprom_out(&r, 0);
210 1.9.6.2 tls
211 1.9.6.2 tls /* set address */
212 1.9.6.2 tls for (i = 0; i < 6; i++, addr <<= 1)
213 1.9.6.2 tls __spd_eeprom_out(&r, addr & 0x20);
214 1.9.6.2 tls
215 1.9.6.2 tls /* get data */
216 1.9.6.2 tls for (i = 0; i < n; i++, data++)
217 1.9.6.2 tls for (*data = 0, j = 15; j >= 0; j--)
218 1.9.6.2 tls *data |= (__spd_eeprom_in(&r) << j);
219 1.9.6.2 tls
220 1.9.6.2 tls /* chip select low */
221 1.9.6.2 tls r &= ~(SPD_IO_CS | SPD_IO_IN | SPD_IO_CLK);
222 1.9.6.2 tls _reg_write_1(SPD_IO_DATA_REG8, r);
223 1.9.6.2 tls delay(2);
224 1.9.6.2 tls
225 1.9.6.2 tls _intr_resume(s);
226 1.9.6.2 tls }
227 1.9.6.2 tls
228 1.9.6.2 tls void
229 1.9.6.2 tls __spd_eeprom_out(u_int8_t *rp, int onoff)
230 1.9.6.2 tls {
231 1.9.6.2 tls u_int8_t r = *rp;
232 1.9.6.2 tls
233 1.9.6.2 tls if (onoff)
234 1.9.6.2 tls r |= SPD_IO_IN;
235 1.9.6.2 tls else
236 1.9.6.2 tls r &= ~SPD_IO_IN;
237 1.9.6.2 tls
238 1.9.6.2 tls r &= ~SPD_IO_CLK;
239 1.9.6.2 tls _reg_write_1(SPD_IO_DATA_REG8, r);
240 1.9.6.2 tls delay(1);
241 1.9.6.2 tls
242 1.9.6.2 tls r |= SPD_IO_CLK;
243 1.9.6.2 tls _reg_write_1(SPD_IO_DATA_REG8, r);
244 1.9.6.2 tls delay(1);
245 1.9.6.2 tls
246 1.9.6.2 tls r &= ~SPD_IO_CLK;
247 1.9.6.2 tls _reg_write_1(SPD_IO_DATA_REG8, r);
248 1.9.6.2 tls delay(1);
249 1.9.6.2 tls
250 1.9.6.2 tls *rp = r;
251 1.9.6.2 tls }
252 1.9.6.2 tls
253 1.9.6.2 tls int
254 1.9.6.2 tls __spd_eeprom_in(u_int8_t *rp)
255 1.9.6.2 tls {
256 1.9.6.2 tls int ret;
257 1.9.6.2 tls u_int8_t r = *rp;
258 1.9.6.2 tls
259 1.9.6.2 tls r &= ~(SPD_IO_IN | SPD_IO_CLK);
260 1.9.6.2 tls _reg_write_1(SPD_IO_DATA_REG8, r);
261 1.9.6.2 tls delay(1);
262 1.9.6.2 tls
263 1.9.6.2 tls r |= SPD_IO_CLK;
264 1.9.6.2 tls _reg_write_1(SPD_IO_DATA_REG8, r);
265 1.9.6.2 tls delay(1);
266 1.9.6.2 tls ret = (_reg_read_1(SPD_IO_DATA_REG8) >> 4) & 0x1;
267 1.9.6.2 tls
268 1.9.6.2 tls r &= ~SPD_IO_CLK;
269 1.9.6.2 tls _reg_write_1(SPD_IO_DATA_REG8, r);
270 1.9.6.2 tls delay(1);
271 1.9.6.2 tls
272 1.9.6.2 tls *rp = r;
273 1.9.6.2 tls
274 1.9.6.2 tls return (ret);
275 1.9.6.2 tls }
276 1.9.6.2 tls
277