2 #include "libopenbios/bindings.h"
3 #include "drivers/drivers.h"
4 #include "libc/byteorder.h"
5 #include "libc/vsprintf.h"
12 #define CUDA_DPRINTF(fmt, args...) \
13 do { printk("CUDA - %s: " fmt, __func__ , ##args); } while (0)
15 #define CUDA_DPRINTF(fmt, args...) do { } while (0)
18 #define IO_CUDA_OFFSET 0x00016000
19 #define IO_CUDA_SIZE 0x00002000
21 /* VIA registers - spaced 0x200 bytes apart */
22 #define RS 0x200 /* skip between registers */
23 #define B 0 /* B-side data */
24 #define A RS /* A-side data */
25 #define DIRB (2*RS) /* B-side direction (1=output) */
26 #define DIRA (3*RS) /* A-side direction (1=output) */
27 #define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */
28 #define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */
29 #define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */
30 #define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */
31 #define T2CL (8*RS) /* Timer 2 ctr/latch (low 8 bits) */
32 #define T2CH (9*RS) /* Timer 2 counter (high 8 bits) */
33 #define SR (10*RS) /* Shift register */
34 #define ACR (11*RS) /* Auxiliary control register */
35 #define PCR (12*RS) /* Peripheral control register */
36 #define IFR (13*RS) /* Interrupt flag register */
37 #define IER (14*RS) /* Interrupt enable register */
38 #define ANH (15*RS) /* A-side data, no handshake */
40 /* Bits in B data register: all active low */
41 #define TREQ 0x08 /* Transfer request (input) */
42 #define TACK 0x10 /* Transfer acknowledge (output) */
43 #define TIP 0x20 /* Transfer in progress (output) */
46 #define SR_CTRL 0x1c /* Shift register control bits */
47 #define SR_EXT 0x0c /* Shift on external clock */
48 #define SR_OUT 0x10 /* Shift out if 1 */
50 /* Bits in IFR and IER */
51 #define IER_SET 0x80 /* set bits in IER */
52 #define IER_CLR 0 /* clear bits in IER */
53 #define SR_INT 0x04 /* Shift register full/empty */
55 #define CUDA_BUF_SIZE 16
60 /* CUDA commands (2nd byte) */
61 #define CUDA_GET_TIME 0x03
62 #define CUDA_SET_TIME 0x09
63 #define CUDA_POWERDOWN 0x0a
64 #define CUDA_RESET_SYSTEM 0x11
66 static uint8_t cuda_readb (cuda_t
*dev
, int reg
)
68 return *(volatile uint8_t *)(dev
->base
+ reg
);
71 static void cuda_writeb (cuda_t
*dev
, int reg
, uint8_t val
)
73 *(volatile uint8_t *)(dev
->base
+ reg
) = val
;
76 static void cuda_wait_irq (cuda_t
*dev
)
80 // CUDA_DPRINTF("\n");
82 val
= cuda_readb(dev
, IFR
);
83 cuda_writeb(dev
, IFR
, val
& 0x7f);
91 static int cuda_request (cuda_t
*dev
, uint8_t pkt_type
, const uint8_t *buf
,
92 int buf_len
, uint8_t *obuf
)
96 cuda_writeb(dev
, ACR
, cuda_readb(dev
, ACR
) | SR_OUT
);
97 cuda_writeb(dev
, SR
, pkt_type
);
98 cuda_writeb(dev
, B
, cuda_readb(dev
, B
) & ~TIP
);
100 //CUDA_DPRINTF("Send buf len: %d\n", buf_len);
102 for(i
= 0; i
< buf_len
; i
++) {
104 cuda_writeb(dev
, SR
, buf
[i
]);
105 cuda_writeb(dev
, B
, cuda_readb(dev
, B
) ^ TACK
);
109 cuda_writeb(dev
, ACR
, cuda_readb(dev
, ACR
) & ~SR_OUT
);
111 cuda_writeb(dev
, B
, cuda_readb(dev
, B
) | TIP
| TACK
);
117 cuda_writeb(dev
, B
, cuda_readb(dev
, B
) & ~TIP
);
120 val
= cuda_readb(dev
, SR
);
121 if (obuf_len
< CUDA_BUF_SIZE
)
122 obuf
[obuf_len
++] = val
;
123 if (cuda_readb(dev
, B
) & TREQ
)
125 cuda_writeb(dev
, B
, cuda_readb(dev
, B
) ^ TACK
);
127 cuda_writeb(dev
, B
, cuda_readb(dev
, B
) | TIP
| TACK
);
132 // CUDA_DPRINTF("Got len: %d\n", obuf_len);
139 static int cuda_adb_req (void *host
, const uint8_t *snd_buf
, int len
,
142 uint8_t buffer
[CUDA_BUF_SIZE
], *pos
;
144 // CUDA_DPRINTF("len: %d %02x\n", len, snd_buf[0]);
145 len
= cuda_request(host
, ADB_PACKET
, snd_buf
, len
, buffer
);
146 if (len
> 1 && buffer
[0] == ADB_PACKET
) {
153 memcpy(rcv_buf
, pos
, len
);
159 DECLARE_UNNAMED_NODE(ob_cuda
, INSTALL_OPEN
, sizeof(int));
161 static cuda_t
*main_cuda
;
164 ppc32_reset_all(void)
166 uint8_t cmdbuf
[2], obuf
[64];
168 cmdbuf
[0] = CUDA_RESET_SYSTEM
;
169 cuda_request(main_cuda
, CUDA_PACKET
, cmdbuf
, sizeof(cmdbuf
), obuf
);
175 uint8_t cmdbuf
[2], obuf
[64];
177 cmdbuf
[0] = CUDA_POWERDOWN
;
178 cuda_request(main_cuda
, CUDA_PACKET
, cmdbuf
, sizeof(cmdbuf
), obuf
);
182 ob_cuda_initialize (int *idx
)
184 phandle_t ph
=get_cur_dev();
187 push_str("via-cuda");
188 fword("device-type");
190 set_int_property(ph
, "#address-cells", 1);
191 set_int_property(ph
, "#size-cells", 0);
193 set_property(ph
, "compatible", "cuda", 5);
195 props
[0] = __cpu_to_be32(IO_CUDA_OFFSET
);
196 props
[1] = __cpu_to_be32(IO_CUDA_SIZE
);
198 set_property(ph
, "reg", (char *)&props
, sizeof(props
));
200 /* on newworld machines the cuda is on interrupt 0x19 */
204 NEWWORLD(set_property(ph
, "interrupts", (char *)props
, sizeof(props
)));
205 NEWWORLD(set_int_property(ph
, "#interrupt-cells", 2));
207 /* we emulate an oldworld hardware, so we must use
208 * non-standard oldworld property (needed by linux 2.6.18)
211 OLDWORLD(set_int_property(ph
, "AAPL,interrupts", 0x12));
213 bind_func("ppc32-reset-all", ppc32_reset_all
);
214 push_str("' ppc32-reset-all to reset-all");
219 ob_cuda_open(int *idx
)
225 ob_cuda_close(int *idx
)
229 NODE_METHODS(ob_cuda
) = {
230 { NULL
, ob_cuda_initialize
},
231 { "open", ob_cuda_open
},
232 { "close", ob_cuda_close
},
235 DECLARE_UNNAMED_NODE(rtc
, INSTALL_OPEN
, sizeof(int));
244 * get-time ( -- second minute hour day month year )
248 static const int days_month
[12] =
249 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
250 static const int days_month_leap
[12] =
251 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
253 static inline int is_leap(int year
)
255 return ((year
% 4 == 0) && (year
% 100 != 0)) || (year
% 400 == 0);
259 rtc_get_time(int *idx
)
261 uint8_t cmdbuf
[2], obuf
[64];
262 ucell second
, minute
, hour
, day
, month
, year
;
267 cmdbuf
[0] = CUDA_GET_TIME
;
268 cuda_request(main_cuda
, CUDA_PACKET
, cmdbuf
, sizeof(cmdbuf
), obuf
);
270 /* seconds since 01/01/1904 */
272 now
= (obuf
[3] << 24) + (obuf
[4] << 16) + (obuf
[5] << 8) + obuf
[6];
283 year
= now
* 100 / 36525;
284 now
-= year
* 36525 / 100;
287 days
= is_leap(year
) ? days_month_leap
: days_month
;
292 if (now
<= current
+ days
[month
]) {
295 current
+= days
[month
];
311 * set-time ( second minute hour day month year -- )
316 rtc_set_time(int *idx
)
318 uint8_t cmdbuf
[5], obuf
[3];
319 ucell second
, minute
, hour
, day
, month
, year
;
322 unsigned int nb_days
;
332 days
= is_leap(year
) ? days_month_leap
: days_month
;
333 nb_days
= (year
- 1904) * 36525 / 100 + day
;
334 for (i
= 0; i
< month
- 1; i
++)
337 now
= (((nb_days
* 24) + hour
) * 60 + minute
) * 60 + second
;
339 cmdbuf
[0] = CUDA_SET_TIME
;
340 cmdbuf
[1] = now
>> 24;
341 cmdbuf
[2] = now
>> 16;
342 cmdbuf
[3] = now
>> 8;
345 cuda_request(main_cuda
, CUDA_PACKET
, cmdbuf
, sizeof(cmdbuf
), obuf
);
348 NODE_METHODS(rtc
) = {
349 { "open", rtc_open
},
350 { "get-time", rtc_get_time
},
351 { "set-time", rtc_set_time
},
357 phandle_t ph
, aliases
;
360 snprintf(buf
, sizeof(buf
), "%s/rtc", path
);
361 REGISTER_NAMED_NODE(rtc
, buf
);
364 set_property(ph
, "device_type", "rtc", 4);
365 set_property(ph
, "compatible", "rtc", 4);
367 aliases
= find_dev("/aliases");
368 set_property(aliases
, "rtc", buf
, strlen(buf
) + 1);
372 cuda_t
*cuda_init (const char *path
, phys_addr_t base
)
378 base
+= IO_CUDA_OFFSET
;
379 CUDA_DPRINTF(" base=" FMT_plx
"\n", base
);
380 cuda
= malloc(sizeof(cuda_t
));
384 snprintf(buf
, sizeof(buf
), "%s/via-cuda", path
);
385 REGISTER_NAMED_NODE(ob_cuda
, buf
);
387 aliases
= find_dev("/aliases");
388 set_property(aliases
, "via-cuda", buf
, strlen(buf
) + 1);
391 cuda_writeb(cuda
, B
, cuda_readb(cuda
, B
) | TREQ
| TIP
);
392 #ifdef CONFIG_DRIVER_ADB
393 cuda
->adb_bus
= adb_bus_new(cuda
, &cuda_adb_req
);
394 if (cuda
->adb_bus
== NULL
) {
398 adb_bus_init(buf
, cuda
->adb_bus
);
406 bind_func("poweroff", ppc32_poweroff
);