; Crystal Chip hardware interface library
;

CC_MAGIC1               EQU 0xC0
CC_MAGIC2               EQU 0xCA

CC_WRITE_EEP            EQU 0x00
CC_READ_EEP             EQU 0x81
CC_SET_BIOS_CTRL        EQU 0x02
CC_SET_AUTH_CTRL        EQU 0x03
CC_DISABLE_IF           EQU 0x04
CC_WRITE_SRAM           EQU 0x05

; Bits for CC BIOS_CTRL register
BIOS_MCEXEC_EN          EQU (1 << 0)
BIOS_MM16_EN            EQU (1 << 1)
BIOS_LOGO_EN            EQU (1 << 2)
BIOS_READKEY_EN         EQU (1 << 3)
BIOS_MCBOOT_EN          EQU (1 << 4)
BIOS_OSDBOOT_EN         EQU (1 << 5)

; Bits for CC AUTH_CTRL register.
AUTH_MECHA_EN           EQU (1 << 0)
AUTH_SCEX_EN            EQU (1 << 1)

; Bits for PS1 disc authentication region in the CC Auth Control register
AUTH_SCEI               EQU (0 << 2)
AUTH_SCEA               EQU (1 << 2)
AUTH_SCEE               EQU (2 << 2)

CC_sendCmdPkt           PROC

                        addiu       sp, sp, -0x10
                        sw          ra, 0x00(sp)
                        sw          s0, 0x04(sp)
                        sw          s1, 0x08(sp)

                        or          s0, zero, a0
                        lui         s1, 0x1FC0

_l1:
                        li          at, CC_MAGIC1
                        sb          at, 0x01AD(s1)
                        li          at, CC_MAGIC2
                        sb          at, 0x01AD(s1)

                        li          t0, 0                               ; addsum = 0
                        li          t1, 0                               ; i = 0
_l2:
                        addu        at, s0, t1
                        lbu         v0, 0x00(at)
                        sb          v0, 0x01AD(s1)
                        sync.p
                        addiu       t1, t1, 1
                        sltiu       at, t1, 4
                        bne         at, zero, _l2
                        addu        t0, t0, v0                          ; addsum += pkt[i]

                        sb          t0, 0x01AD(s1)                      ; write the addsum
                        sync.p
                        lbu         v0, 0x01AD(s1)                      ; get result
                        andi        v0, v0, 0xF0
                        bnez        v0, _l1                             ; start over if (result & 0xF0) != 0
                        nop

                        lbu         at, 0x00(a0)
                        andi        at, at, 0x80
                        beq         at, zero, _done                     ; has a result
                        nop

                        jal         udelay                              ; delay 10 ms
                        li          a0, 10

                        lbu         v0, 0x01AD(s1)                      ; result
                        lbu         at, 0x01AD(s1)                      ; result2
                        xori        at, at, 0xFF
                        bne         at, v0, _l1                         ; start over if 2nd result != ~(result2)
                        nop

_done:
                        lw          ra, 0x00(sp)
                        lw          s0, 0x04(sp)
                        lw          s1, 0x08(sp)
                        jr          ra
                        addiu       sp, sp, 0x10

CC_sendCmdPkt           ENDP


; !!! Not sure how accurate this is !!!
udelay                  PROC

                        li          t0, 50

_l1:
                        addiu       t0, t0, -1
                        nop
                        nop
                        nop
                        nop
                        bgtz        t0, _l1
                        nop

                        addiu       a0, a0, -1
                        bgtz        a0, _l1
                        li          t0, 50

                        jr          ra
                        nop

udelay                  ENDP

IF _FNO_CC_SetBIOSCtrl == 0
CC_SetBIOSCtrl          PROC

                        addiu       sp, sp, -0x20
                        sw          ra, 0x00(sp)

                        li          at, CC_SET_BIOS_CTRL
                        sw          at, 0x10(sp)

                        sb          a0, 0x11(sp)

                        jal         CC_sendCmdPkt
                        addiu       a0, sp, 0x10

                        lw          ra, 0x00(sp)
                        jr          ra
                        addiu       sp, sp, 0x20

CC_SetBIOSCtrl          ENDP
ENDIF

IF _FNO_CC_SetAuthCtrl == 0
CC_SetAuthCtrl          PROC

                        addiu       sp, sp, -0x20
                        sw          ra, 0x00(sp)

                        li          at, CC_SET_AUTH_CTRL
                        sw          at, 0x10(sp)

                        sb          a0, 0x11(sp)

                        jal         CC_sendCmdPkt
                        addiu       a0, sp, 0x10

                        lw          ra, 0x00(sp)
                        jr          ra
                        addiu       sp, sp, 0x20

CC_SetAuthCtrl          ENDP
ENDIF

IF _FNO_CC_DisableIF == 0
CC_DisableIF            PROC

                        addiu       sp, sp, -0x20
                        sw          ra, 0x00(sp)

                        li          at, CC_DISABLE_IF
                        sw          at, 0x10(sp)

                        li          at, 0xFF
                        sb          at, 0x11(sp)
                        sb          at, 0x12(sp)
                        jal         CC_sendCmdPkt
                        addiu       a0, sp, 0x10

                        lw          ra, 0x00(sp)
                        jr          ra
                        addiu       sp, sp, 0x20

CC_DisableIF            ENDP
ENDIF

IF _FNO_CC_WriteSRAM == 0
CC_WriteSRAM            PROC

                        addiu       sp, sp, -0x20
                        sw          ra, 0x00(sp)
                        sw          s0, 0x04(sp)
                        sw          s1, 0x08(sp)
                        sw          s2, 0x0C(sp)

                        or          s0, zero, a0                        ; s0 = addr
                        or          s1, zero, a1                        ; s1 = buf
                        or          s2, zero, a2                        ; s2 = len
_l1:

                        li          at, CC_WRITE_SRAM
                        sb          at, 0x10(sp)

                        srl         at, s0, 8
                        andi        at, at, 0xFF
                        sb          at, 0x11(sp)

                        andi        at, s0, 0xFF
                        sb          at, 0x12(sp)

                        lbu         at, 0x00(s1)
                        sb          at, 0x13(sp)

                        jal         CC_sendCmdPkt
                        addiu       a0, sp, 0x10

                        addiu       s0, s0, 1                           ; addr++
                        addiu       s2, s2, -1                          ; len--
                        bgtz        s2, _l1
                        addiu       s1, s1, 1                           ; buf++

                        lw          ra, 0x00(sp)
                        lw          s0, 0x04(sp)
                        lw          s1, 0x08(sp)
                        lw          s2, 0x0C(sp)
                        jr          ra
                        addiu       sp, sp, 0x20

CC_WriteSRAM            ENDP
ENDIF

IF _FNO_CC_ReadEEPROM == 0
CC_ReadEEPROM           PROC

                        addiu       sp, sp, -0x20
                        sw          ra, 0x00(sp)
                        sw          s0, 0x04(sp)
                        sw          s1, 0x08(sp)
                        sw          s2, 0x0C(sp)

                        or          s0, zero, a0                        ; s0 = addr
                        or          s1, zero, a1                        ; s1 = buf
                        or          s2, zero, a2                        ; s2 = len

_l1:

                        li          at, CC_READ_EEP
                        sb          at, 0x10(sp)

                        srl         at, s0, 8
                        andi        at, at, 0xFF
                        sb          at, 0x11(sp)

                        andi        at, s0, 0xFF
                        sb          at, 0x12(sp)

                        sb          zero, 0x13(sp)

                        jal         CC_sendCmdPkt
                        addiu       a0, sp, 0x10

                        sb          v0, 0x00(s1)

                        addiu       s0, s0, 1                           ; addr++
                        addiu       s2, s2, -1                          ; len--
                        bgtz        s2, _l1
                        addiu       s1, s1, 1                           ; buf++

                        lw          ra, 0x00(sp)
                        lw          s0, 0x04(sp)
                        lw          s1, 0x08(sp)
                        lw          s2, 0x0C(sp)
                        jr          ra
                        addiu       sp, sp, 0x20

CC_ReadEEPROM           ENDP
ENDIF
