Powerbook firmware!
[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         if (phase > 0)\r
127         {\r
128                 if (phase & __scsiphase_msg)\r
129                 {\r
130                         SCSI_SetPin(SCSI_Out_MSG);\r
131                 }\r
132                 else\r
133                 {\r
134                         SCSI_ClearPin(SCSI_Out_MSG);\r
135                 }\r
136 \r
137                 if (phase & __scsiphase_cd)\r
138                 {\r
139                         SCSI_SetPin(SCSI_Out_CD);\r
140                 }\r
141                 else\r
142                 {\r
143                         SCSI_ClearPin(SCSI_Out_CD);\r
144                 }\r
145 \r
146                 SCSI_CTL_IO_Write(phase & __scsiphase_io ? 1 : 0);\r
147         }\r
148         else\r
149         {\r
150                 SCSI_ClearPin(SCSI_Out_MSG);\r
151                 SCSI_ClearPin(SCSI_Out_CD);\r
152                 SCSI_CTL_IO_Write(0);\r
153         }\r
154         busSettleDelay();\r
155 }\r
156 \r
157 void scsiPhyReset()\r
158 {\r
159         // Set the Clear bits for both SCSI device FIFOs\r
160         scsiTarget_AUX_CTL = scsiTarget_AUX_CTL | 0x03;\r
161 \r
162         // Trigger RST outselves.  It is connected to the datapath and will\r
163         // ensure it returns to the idle state.  The datapath runs at the BUS clk\r
164         // speed (ie. same as the CPU), so we can be sure it is active for a sufficient\r
165         // duration.\r
166         SCSI_SetPin(SCSI_Out_RST);\r
167 \r
168         SCSI_CTL_IO_Write(0);\r
169         SCSI_ClearPin(SCSI_Out_ATN);\r
170         SCSI_ClearPin(SCSI_Out_BSY);\r
171         SCSI_ClearPin(SCSI_Out_ACK);\r
172         SCSI_ClearPin(SCSI_Out_RST);\r
173         SCSI_ClearPin(SCSI_Out_SEL);\r
174         SCSI_ClearPin(SCSI_Out_REQ);\r
175         SCSI_ClearPin(SCSI_Out_MSG);\r
176         SCSI_ClearPin(SCSI_Out_CD);\r
177 \r
178         // Allow the FIFOs to fill up again.\r
179         SCSI_ClearPin(SCSI_Out_RST);\r
180         scsiTarget_AUX_CTL = scsiTarget_AUX_CTL & ~(0x03);\r
181 }\r
182 \r
183 void scsiPhyInit()\r
184 {\r
185         SCSI_RST_ISR_StartEx(scsiResetISR);\r
186 \r
187         // Interrupts may have already been directed to the (empty)\r
188         // standard ISR generated by PSoC Creator.\r
189         SCSI_RST_ClearInterrupt();\r
190 }\r