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