Merge Powerbook pcb updates
[SCSI2SD.git] / software / SCSI2SD / src / scsiPhy.c
1 //      Copyright (C) 2013 Michael McMaster <michael@codesrc.com>\r
2 //\r
3 //      This file is part of SCSI2SD.\r
4 //\r
5 //      SCSI2SD is free software: you can redistribute it and/or modify\r
6 //      it under the terms of the GNU General Public License as published by\r
7 //      the Free Software Foundation, either version 3 of the License, or\r
8 //      (at your option) any later version.\r
9 //\r
10 //      SCSI2SD is distributed in the hope that it will be useful,\r
11 //      but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 //      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 //      GNU General Public License for more details.\r
14 //\r
15 //      You should have received a copy of the GNU General Public License\r
16 //      along with SCSI2SD.  If not, see <http://www.gnu.org/licenses/>.\r
17 \r
18 #include "device.h"\r
19 #include "scsi.h"\r
20 #include "scsiPhy.h"\r
21 #include "bits.h"\r
22 \r
23 #define scsiTarget_AUX_CTL (* (reg8 *) scsiTarget_datapath__DP_AUX_CTL_REG)\r
24 \r
25 CY_ISR_PROTO(scsiResetISR);\r
26 CY_ISR(scsiResetISR)\r
27 {\r
28         scsiDev.resetFlag = 1;\r
29         SCSI_RST_ClearInterrupt();\r
30 }\r
31 \r
32 uint8 scsiReadDBxPins()\r
33 {\r
34         return\r
35                 (SCSI_ReadPin(SCSI_In_DBx_DB7) << 7) |\r
36                 (SCSI_ReadPin(SCSI_In_DBx_DB6) << 6) |\r
37                 (SCSI_ReadPin(SCSI_In_DBx_DB5) << 5) |\r
38                 (SCSI_ReadPin(SCSI_In_DBx_DB4) << 4) |\r
39                 (SCSI_ReadPin(SCSI_In_DBx_DB3) << 3) |\r
40                 (SCSI_ReadPin(SCSI_In_DBx_DB2) << 2) |\r
41                 (SCSI_ReadPin(SCSI_In_DBx_DB1) << 1) |\r
42                 SCSI_ReadPin(SCSI_In_DBx_DB0);          \r
43 }\r
44 \r
45 uint8 scsiReadByte(void)\r
46 {\r
47         while (!(CY_GET_REG8(scsiTarget_StatusReg__STATUS_REG) & 1) &&\r
48                 !scsiDev.resetFlag) {}\r
49         CY_SET_REG8(scsiTarget_datapath__F0_REG, 0);\r
50         while (!(CY_GET_REG8(scsiTarget_StatusReg__STATUS_REG) & 2) &&\r
51                 !scsiDev.resetFlag) {}\r
52                 \r
53         while (SCSI_ReadPin(SCSI_In_ACK) && !scsiDev.resetFlag) {}\r
54                 \r
55         return CY_GET_REG8(scsiTarget_datapath__F1_REG);\r
56 }\r
57 \r
58 void scsiRead(uint8* data, uint32 count)\r
59 {\r
60         int prep = 0;\r
61         int i = 0;\r
62 \r
63         while (i < count && !scsiDev.resetFlag)\r
64         {\r
65                 if (prep < count && (CY_GET_REG8(scsiTarget_StatusReg__STATUS_REG) & 1))\r
66                 {\r
67                         CY_SET_REG8(scsiTarget_datapath__F0_REG, 0);\r
68                         ++prep;\r
69                 }\r
70                 if ((CY_GET_REG8(scsiTarget_StatusReg__STATUS_REG) & 2))\r
71                 {\r
72                         data[i] =  CY_GET_REG8(scsiTarget_datapath__F1_REG);\r
73                         ++i;\r
74                 }\r
75         }\r
76         while (SCSI_ReadPin(SCSI_In_ACK) && !scsiDev.resetFlag) {}\r
77 \r
78 }\r
79 \r
80 void scsiWriteByte(uint8 value)\r
81 {\r
82         while (!(CY_GET_REG8(scsiTarget_StatusReg__STATUS_REG) & 1) &&\r
83                 !scsiDev.resetFlag) {}\r
84         CY_SET_REG8(scsiTarget_datapath__F0_REG, value);\r
85 \r
86         // TODO maybe move this TX EMPTY check to scsiEnterPhase ?\r
87         //while (!(CY_GET_REG8(scsiTarget_StatusReg__STATUS_REG) & 4)) {}\r
88         while (!(CY_GET_REG8(scsiTarget_StatusReg__STATUS_REG) & 2) &&\r
89                 !scsiDev.resetFlag) {}\r
90         value = CY_GET_REG8(scsiTarget_datapath__F1_REG);\r
91         \r
92         while (SCSI_ReadPin(SCSI_In_ACK) && !scsiDev.resetFlag) {}\r
93 }\r
94 \r
95 void scsiWrite(uint8* data, uint32 count)\r
96 {\r
97         int prep = 0;\r
98         int i = 0;\r
99 \r
100         while (i < count && !scsiDev.resetFlag)\r
101         {\r
102                 if (prep < count && (CY_GET_REG8(scsiTarget_StatusReg__STATUS_REG) & 1))\r
103                 {\r
104                         CY_SET_REG8(scsiTarget_datapath__F0_REG, data[prep]);\r
105                         ++prep;\r
106                 }\r
107                 if ((CY_GET_REG8(scsiTarget_StatusReg__STATUS_REG) & 2))\r
108                 {\r
109                         CY_GET_REG8(scsiTarget_datapath__F1_REG);\r
110                         ++i;\r
111                 }\r
112         }\r
113         \r
114         while (SCSI_ReadPin(SCSI_In_ACK) && !scsiDev.resetFlag) {}\r
115 }\r
116 \r
117 static void busSettleDelay(void)\r
118 {\r
119         // Data Release time (switching IO) = 400ns\r
120         // + Bus Settle time (switching phase) = 400ns.\r
121         CyDelayUs(1); // Close enough.\r
122 }\r
123 \r
124 void scsiEnterPhase(int phase)\r
125 {\r
126         int newPhase = phase > 0 ? phase : 0;\r
127         if (newPhase != SCSI_CTL_PHASE_Read())\r
128         {\r
129                 SCSI_CTL_PHASE_Write(phase > 0 ? phase : 0);\r
130                 busSettleDelay();\r
131         }\r
132 }\r
133 \r
134 void scsiPhyReset()\r
135 {\r
136         // Set the Clear bits for both SCSI device FIFOs\r
137         scsiTarget_AUX_CTL = scsiTarget_AUX_CTL | 0x03;\r
138 \r
139         // Trigger RST outselves.  It is connected to the datapath and will\r
140         // ensure it returns to the idle state.  The datapath runs at the BUS clk\r
141         // speed (ie. same as the CPU), so we can be sure it is active for a sufficient\r
142         // duration.\r
143         SCSI_SetPin(SCSI_Out_RST);\r
144 \r
145         SCSI_CTL_PHASE_Write(0);\r
146         SCSI_ClearPin(SCSI_Out_ATN);\r
147         SCSI_ClearPin(SCSI_Out_BSY);\r
148         SCSI_ClearPin(SCSI_Out_ACK);\r
149         SCSI_ClearPin(SCSI_Out_RST);\r
150         SCSI_ClearPin(SCSI_Out_SEL);\r
151         SCSI_ClearPin(SCSI_Out_REQ);\r
152 \r
153         // Allow the FIFOs to fill up again.\r
154         SCSI_ClearPin(SCSI_Out_RST);\r
155         scsiTarget_AUX_CTL = scsiTarget_AUX_CTL & ~(0x03);\r
156 }\r
157 \r
158 void scsiPhyInit()\r
159 {\r
160         SCSI_RST_ISR_StartEx(scsiResetISR);\r
161 \r
162         // Interrupts may have already been directed to the (empty)\r
163         // standard ISR generated by PSoC Creator.\r
164         SCSI_RST_ClearInterrupt();\r
165 }\r