| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * Apple Peripheral System Controller (PSC) | 
|  | 3 | * | 
|  | 4 | * The PSC is used on the AV Macs to control IO functions not handled | 
|  | 5 | * by the VIAs (Ethernet, DSP, SCC, Sound). This includes nine DMA | 
|  | 6 | * channels. | 
|  | 7 | * | 
|  | 8 | * The first seven DMA channels appear to be "one-shot" and are actually | 
|  | 9 | * sets of two channels; one member is active while the other is being | 
|  | 10 | * configured, and then you flip the active member and start all over again. | 
|  | 11 | * The one-shot channels are grouped together and are: | 
|  | 12 | * | 
|  | 13 | * 1. SCSI | 
|  | 14 | * 2. Ethernet Read | 
|  | 15 | * 3. Ethernet Write | 
|  | 16 | * 4. Floppy Disk Controller | 
|  | 17 | * 5. SCC Channel A Receive | 
|  | 18 | * 6. SCC Channel B Receive | 
|  | 19 | * 7. SCC Channel A Transmit | 
|  | 20 | * | 
|  | 21 | * The remaining two channels are handled somewhat differently. They appear | 
|  | 22 | * to be closely tied and share one set of registers. They also seem to run | 
|  | 23 | * continuously, although how you keep the buffer filled in this scenario is | 
|  | 24 | * not understood as there seems to be only one input and one output buffer | 
|  | 25 | * pointer. | 
|  | 26 | * | 
|  | 27 | * Much of this was extrapolated from what was known about the Ethernet | 
|  | 28 | * registers and subsequently confirmed using MacsBug (ie by pinging the | 
|  | 29 | * machine with easy-to-find patterns and looking for them in the DMA | 
|  | 30 | * buffers, or by sending a file over the serial ports and finding the | 
|  | 31 | * file in the buffers.) | 
|  | 32 | * | 
|  | 33 | * 1999-05-25 (jmt) | 
|  | 34 | */ | 
|  | 35 |  | 
|  | 36 | #define PSC_BASE	(0x50F31000) | 
|  | 37 |  | 
|  | 38 | /* | 
|  | 39 | * The IER/IFR registers work like the VIA, except that it has 4 | 
|  | 40 | * of them each on different interrupt levels, and each register | 
|  | 41 | * set only seems to handle four interrupts instead of seven. | 
|  | 42 | * | 
|  | 43 | * To access a particular set of registers, add 0xn0 to the base | 
|  | 44 | * where n = 3,4,5 or 6. | 
|  | 45 | */ | 
|  | 46 |  | 
|  | 47 | #define pIFRbase	0x100 | 
|  | 48 | #define pIERbase	0x104 | 
|  | 49 |  | 
|  | 50 | /* | 
|  | 51 | * One-shot DMA control registers | 
|  | 52 | */ | 
|  | 53 |  | 
|  | 54 | #define PSC_MYSTERY	0x804 | 
|  | 55 |  | 
|  | 56 | #define PSC_CTL_BASE	0xC00 | 
|  | 57 |  | 
|  | 58 | #define PSC_SCSI_CTL	0xC00 | 
|  | 59 | #define PSC_ENETRD_CTL  0xC10 | 
|  | 60 | #define PSC_ENETWR_CTL  0xC20 | 
|  | 61 | #define PSC_FDC_CTL	0xC30 | 
|  | 62 | #define PSC_SCCA_CTL	0xC40 | 
|  | 63 | #define PSC_SCCB_CTL	0xC50 | 
|  | 64 | #define PSC_SCCATX_CTL	0xC60 | 
|  | 65 |  | 
|  | 66 | /* | 
|  | 67 | * DMA channels. Add +0x10 for the second channel in the set. | 
|  | 68 | * You're supposed to use one channel while the other runs and | 
|  | 69 | * then flip channels and do the whole thing again. | 
|  | 70 | */ | 
|  | 71 |  | 
|  | 72 | #define PSC_ADDR_BASE	0x1000 | 
|  | 73 | #define PSC_LEN_BASE	0x1004 | 
|  | 74 | #define PSC_CMD_BASE	0x1008 | 
|  | 75 |  | 
|  | 76 | #define PSC_SET0	0x00 | 
|  | 77 | #define PSC_SET1	0x10 | 
|  | 78 |  | 
|  | 79 | #define PSC_SCSI_ADDR	0x1000	/* confirmed */ | 
|  | 80 | #define PSC_SCSI_LEN	0x1004	/* confirmed */ | 
|  | 81 | #define PSC_SCSI_CMD	0x1008	/* confirmed */ | 
|  | 82 | #define PSC_ENETRD_ADDR 0x1020	/* confirmed */ | 
|  | 83 | #define PSC_ENETRD_LEN  0x1024	/* confirmed */ | 
|  | 84 | #define PSC_ENETRD_CMD  0x1028	/* confirmed */ | 
|  | 85 | #define PSC_ENETWR_ADDR 0x1040	/* confirmed */ | 
|  | 86 | #define PSC_ENETWR_LEN  0x1044	/* confirmed */ | 
|  | 87 | #define PSC_ENETWR_CMD  0x1048	/* confirmed */ | 
|  | 88 | #define PSC_FDC_ADDR	0x1060	/* strongly suspected */ | 
|  | 89 | #define PSC_FDC_LEN	0x1064	/* strongly suspected */ | 
|  | 90 | #define PSC_FDC_CMD	0x1068	/* strongly suspected */ | 
|  | 91 | #define PSC_SCCA_ADDR	0x1080	/* confirmed */ | 
|  | 92 | #define PSC_SCCA_LEN	0x1084	/* confirmed */ | 
|  | 93 | #define PSC_SCCA_CMD	0x1088	/* confirmed */ | 
|  | 94 | #define PSC_SCCB_ADDR	0x10A0	/* confirmed */ | 
|  | 95 | #define PSC_SCCB_LEN	0x10A4	/* confirmed */ | 
|  | 96 | #define PSC_SCCB_CMD	0x10A8	/* confirmed */ | 
|  | 97 | #define PSC_SCCATX_ADDR	0x10C0	/* confirmed */ | 
|  | 98 | #define PSC_SCCATX_LEN	0x10C4	/* confirmed */ | 
|  | 99 | #define PSC_SCCATX_CMD	0x10C8	/* confirmed */ | 
|  | 100 |  | 
|  | 101 | /* | 
|  | 102 | * Free-running DMA registers. The only part known for sure are the bits in | 
|  | 103 | * the control register, the buffer addresses and the buffer length. Everything | 
|  | 104 | * else is anybody's guess. | 
|  | 105 | * | 
|  | 106 | * These registers seem to be mirrored every thirty-two bytes up until offset | 
|  | 107 | * 0x300. It's safe to assume then that a new set of registers starts there. | 
|  | 108 | */ | 
|  | 109 |  | 
|  | 110 | #define PSC_SND_CTL	0x200	/* | 
|  | 111 | * [ 16-bit ] | 
|  | 112 | * Sound (Singer?) control register. | 
|  | 113 | * | 
|  | 114 | * bit 0  : ???? | 
|  | 115 | * bit 1  : ???? | 
|  | 116 | * bit 2  : Set to one to enable sound | 
|  | 117 | *          output. Possibly a mute flag. | 
|  | 118 | * bit 3  : ???? | 
|  | 119 | * bit 4  : ???? | 
|  | 120 | * bit 5  : ???? | 
|  | 121 | * bit 6  : Set to one to enable pass-thru | 
|  | 122 | *          audio. In this mode the audio data | 
|  | 123 | *          seems to appear in both the input | 
|  | 124 | *          buffer and the output buffer. | 
|  | 125 | * bit 7  : Set to one to activate the | 
|  | 126 | *          sound input DMA or zero to | 
|  | 127 | *          disable it. | 
|  | 128 | * bit 8  : Set to one to activate the | 
|  | 129 | *          sound output DMA or zero to | 
|  | 130 | *          disable it. | 
|  | 131 | * bit 9  : \ | 
|  | 132 | * bit 11 :  | | 
|  | 133 | *          These two bits control the sample | 
|  | 134 | *          rate. Usually set to binary 10 and | 
|  | 135 | *	    MacOS 8.0 says I'm at 48 KHz. Using | 
|  | 136 | *	    a binary value of 01 makes things | 
|  | 137 | *	    sound about 1/2 speed (24 KHz?) and | 
|  | 138 | *          binary 00 is slower still (22 KHz?) | 
|  | 139 | * | 
|  | 140 | * Setting this to 0x0000 is a good way to | 
|  | 141 | * kill all DMA at boot time so that the | 
|  | 142 | * PSC won't overwrite the kernel image | 
|  | 143 | * with sound data. | 
|  | 144 | */ | 
|  | 145 |  | 
|  | 146 | /* | 
|  | 147 | * 0x0202 - 0x0203 is unused. Writing there | 
|  | 148 | * seems to clobber the control register. | 
|  | 149 | */ | 
|  | 150 |  | 
|  | 151 | #define PSC_SND_SOURCE	0x204	/* | 
|  | 152 | * [ 32-bit ] | 
|  | 153 | * Controls input source and volume: | 
|  | 154 | * | 
|  | 155 | * bits 12-15 : input source volume, 0 - F | 
|  | 156 | * bits 16-19 : unknown, always 0x5 | 
|  | 157 | * bits 20-23 : input source selection: | 
|  | 158 | *                  0x3 = CD Audio | 
|  | 159 | *                  0x4 = External Audio | 
|  | 160 | * | 
|  | 161 | * The volume is definitely not the general | 
|  | 162 | * output volume as it doesn't affect the | 
|  | 163 | * alert sound volume. | 
|  | 164 | */ | 
|  | 165 | #define PSC_SND_STATUS1	0x208	/* | 
|  | 166 | * [ 32-bit ] | 
|  | 167 | * Appears to be a read-only status register. | 
|  | 168 | * The usual value is 0x00400002. | 
|  | 169 | */ | 
|  | 170 | #define PSC_SND_HUH3	0x20C	/* | 
|  | 171 | * [ 16-bit ] | 
|  | 172 | * Unknown 16-bit value, always 0x0000. | 
|  | 173 | */ | 
|  | 174 | #define PSC_SND_BITS2GO	0x20E	/* | 
|  | 175 | * [ 16-bit ] | 
|  | 176 | * Counts down to zero from some constant | 
|  | 177 | * value. The value appears to be the | 
|  | 178 | * number of _bits_ remaining before the | 
|  | 179 | * buffer is full, which would make sense | 
|  | 180 | * since Apple's docs say the sound DMA | 
|  | 181 | * channels are 1 bit wide. | 
|  | 182 | */ | 
|  | 183 | #define PSC_SND_INADDR	0x210	/* | 
|  | 184 | * [ 32-bit ] | 
|  | 185 | * Address of the sound input DMA buffer | 
|  | 186 | */ | 
|  | 187 | #define PSC_SND_OUTADDR	0x214	/* | 
|  | 188 | * [ 32-bit ] | 
|  | 189 | * Address of the sound output DMA buffer | 
|  | 190 | */ | 
|  | 191 | #define PSC_SND_LEN	0x218	/* | 
|  | 192 | * [ 16-bit ] | 
|  | 193 | * Length of both buffers in eight-byte units. | 
|  | 194 | */ | 
|  | 195 | #define PSC_SND_HUH4	0x21A	/* | 
|  | 196 | * [ 16-bit ] | 
|  | 197 | * Unknown, always 0x0000. | 
|  | 198 | */ | 
|  | 199 | #define PSC_SND_STATUS2	0x21C	/* | 
|  | 200 | * [ 16-bit ] | 
|  | 201 | * Appears to e a read-only status register. | 
|  | 202 | * The usual value is 0x0200. | 
|  | 203 | */ | 
|  | 204 | #define PSC_SND_HUH5	0x21E	/* | 
|  | 205 | * [ 16-bit ] | 
|  | 206 | * Unknown, always 0x0000. | 
|  | 207 | */ | 
|  | 208 |  | 
|  | 209 | #ifndef __ASSEMBLY__ | 
|  | 210 |  | 
|  | 211 | extern volatile __u8 *psc; | 
|  | 212 | extern int psc_present; | 
|  | 213 |  | 
|  | 214 | /* | 
|  | 215 | *	Access functions | 
|  | 216 | */ | 
|  | 217 |  | 
|  | 218 | static inline void psc_write_byte(int offset, __u8 data) | 
|  | 219 | { | 
|  | 220 | *((volatile __u8 *)(psc + offset)) = data; | 
|  | 221 | } | 
|  | 222 |  | 
|  | 223 | static inline void psc_write_word(int offset, __u16 data) | 
|  | 224 | { | 
|  | 225 | *((volatile __u16 *)(psc + offset)) = data; | 
|  | 226 | } | 
|  | 227 |  | 
|  | 228 | static inline void psc_write_long(int offset, __u32 data) | 
|  | 229 | { | 
|  | 230 | *((volatile __u32 *)(psc + offset)) = data; | 
|  | 231 | } | 
|  | 232 |  | 
|  | 233 | static inline u8 psc_read_byte(int offset) | 
|  | 234 | { | 
|  | 235 | return *((volatile __u8 *)(psc + offset)); | 
|  | 236 | } | 
|  | 237 |  | 
|  | 238 | static inline u16 psc_read_word(int offset) | 
|  | 239 | { | 
|  | 240 | return *((volatile __u16 *)(psc + offset)); | 
|  | 241 | } | 
|  | 242 |  | 
|  | 243 | static inline u32 psc_read_long(int offset) | 
|  | 244 | { | 
|  | 245 | return *((volatile __u32 *)(psc + offset)); | 
|  | 246 | } | 
|  | 247 |  | 
|  | 248 | #endif /* __ASSEMBLY__ */ |