Rev 1695 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1695 | Rev 2968 | ||
---|---|---|---|
1 | #define FORCED_PIO |
1 | #define FORCED_PIO |
2 | 2 | ||
3 | #include |
3 | #include |
4 | #include "pci.h" |
4 | #include "pci.h" |
5 | #include |
5 | #include |
6 | 6 | ||
7 | #include "geode.h" |
7 | #include "geode.h" |
8 | 8 | ||
9 | #define DBG(format,...) dbgprintf(format,##__VA_ARGS__) |
9 | //#define DBG(format,...) dbgprintf(format,##__VA_ARGS__) |
10 | 10 | #define DBG(format,...) |
|
- | 11 | ||
11 | #define BM0_IRQ 0x04 |
12 | #define BM0_IRQ 0x04 |
12 | #define BM1_IRQ 0x08 |
13 | #define BM1_IRQ 0x08 |
13 | #define BITS_8_TO_16(x) ( ( (long) ((unsigned char) x - 128) ) << 8 ) |
14 | #define BITS_8_TO_16(x) ( ( (long) ((unsigned char) x - 128) ) << 8 ) |
14 | 15 | ||
15 | #define PCI_VENDOR_ID_NS 0x100b |
16 | #define PCI_VENDOR_ID_NS 0x100b |
16 | #define PCI_VENDOR_ID_AMD 0x1022 |
17 | #define PCI_VENDOR_ID_AMD 0x1022 |
17 | 18 | ||
18 | 19 | ||
19 | #ifndef PCI_DEVICE_ID_NS_CS5535_AUDIO |
20 | #ifndef PCI_DEVICE_ID_NS_CS5535_AUDIO |
20 | #define PCI_DEVICE_ID_NS_CS5535_AUDIO 0x002e |
21 | #define PCI_DEVICE_ID_NS_CS5535_AUDIO 0x002e |
21 | #endif |
22 | #endif |
22 | #ifndef PCI_DEVICE_ID_AMD_CS5536_AUDIO |
23 | #ifndef PCI_DEVICE_ID_AMD_CS5536_AUDIO |
23 | #define PCI_DEVICE_ID_AMD_CS5536_AUDIO 0x2093 |
24 | #define PCI_DEVICE_ID_AMD_CS5536_AUDIO 0x2093 |
24 | #endif |
25 | #endif |
25 | 26 | ||
26 | #define ID_DEV_1 ((PCI_DEVICE_ID_NS_CS5535_AUDIO << 16)|PCI_VENDOR_ID_NS) |
27 | #define ID_DEV_1 ((PCI_DEVICE_ID_NS_CS5535_AUDIO << 16)|PCI_VENDOR_ID_NS) |
27 | #define ID_DEV_2 ((PCI_DEVICE_ID_AMD_CS5536_AUDIO << 16)|PCI_VENDOR_ID_AMD) |
28 | #define ID_DEV_2 ((PCI_DEVICE_ID_AMD_CS5536_AUDIO << 16)|PCI_VENDOR_ID_AMD) |
28 | 29 | ||
29 | #define SET 1 |
30 | #define SET 1 |
30 | #define CLEAR 0 |
31 | #define CLEAR 0 |
31 | 32 | ||
32 | int __stdcall srv_sound(ioctl_t *io); |
33 | int __stdcall srv_sound(ioctl_t *io); |
33 | 34 | ||
34 | 35 | ||
35 | PRD_ENTRY __attribute__((aligned(16))) prd_tab[5]; |
36 | PRD_ENTRY __attribute__((aligned(16))) prd_tab[5]; |
36 | 37 | ||
37 | 38 | ||
38 | typedef struct |
39 | typedef struct |
39 | { |
40 | { |
40 | PCITAG pciTag; |
41 | PCITAG pciTag; |
41 | Bool is_iomapped; |
42 | Bool is_iomapped; |
42 | addr_t F3BAR0; |
43 | addr_t F3BAR0; |
43 | 44 | ||
44 | Bool fAD1819A; |
45 | Bool fAD1819A; |
45 | 46 | ||
46 | int CurrentPowerState; |
47 | int CurrentPowerState; |
47 | 48 | ||
48 | addr_t buffer; |
49 | addr_t buffer; |
49 | addr_t buffer_dma; |
50 | addr_t buffer_dma; |
50 | addr_t prd_dma; |
51 | addr_t prd_dma; |
51 | 52 | ||
52 | addr_t irq_line; |
53 | addr_t irq_line; |
53 | u32_t irq_mask; |
54 | u32_t irq_mask; |
54 | 55 | ||
55 | void __stdcall (*callback)(addr_t buffer); |
56 | void __stdcall (*callback)(addr_t buffer); |
56 | }geode_t; |
57 | }geode_t; |
57 | 58 | ||
58 | geode_t geode; |
59 | geode_t geode; |
59 | 60 | ||
60 | 61 | ||
61 | static inline void ctrl_write_32(addr_t reg, u32_t data) |
62 | static inline void ctrl_write_32(addr_t reg, u32_t data) |
62 | { |
63 | { |
63 | reg+= geode.F3BAR0; |
64 | reg+= geode.F3BAR0; |
64 | 65 | ||
65 | #ifdef FORCED_PIO |
66 | #ifdef FORCED_PIO |
66 | out32((u16_t)reg, data); |
67 | out32((u16_t)reg, data); |
67 | #else |
68 | #else |
68 | if(geode.is_iomapped) |
69 | if(geode.is_iomapped) |
69 | out32((u16_t)reg, data); |
70 | out32((u16_t)reg, data); |
70 | else |
71 | else |
71 | *(u32_t*)reg = data; |
72 | *(u32_t*)reg = data; |
72 | #endif |
73 | #endif |
73 | } |
74 | } |
74 | 75 | ||
75 | static inline u32_t ctrl_read_32(addr_t reg) |
76 | static inline u32_t ctrl_read_32(addr_t reg) |
76 | { |
77 | { |
77 | reg+= geode.F3BAR0; |
78 | reg+= geode.F3BAR0; |
78 | #ifdef FORCED_PIO |
79 | #ifdef FORCED_PIO |
79 | return in32((u16_t)reg); |
80 | return in32((u16_t)reg); |
80 | #else |
81 | #else |
81 | if(geode.is_iomapped) |
82 | if(geode.is_iomapped) |
82 | return in32((u16_t)reg); |
83 | return in32((u16_t)reg); |
83 | else |
84 | else |
84 | return *(u32_t*)reg; |
85 | return *(u32_t*)reg; |
85 | #endif |
86 | #endif |
86 | } |
87 | } |
87 | 88 | ||
88 | 89 | ||
89 | 90 | ||
90 | Bool snd_hw_WaitForBit(addr_t offset, u32_t Bit, |
91 | Bool snd_hw_WaitForBit(addr_t offset, u32_t Bit, |
91 | unsigned char Operation, |
92 | unsigned char Operation, |
92 | count_t timeout, |
93 | count_t timeout, |
93 | u32_t *pReturnValue) |
94 | u32_t *pReturnValue) |
94 | { |
95 | { |
95 | volatile u32_t tmp; |
96 | volatile u32_t tmp; |
96 | 97 | ||
97 | tmp = ctrl_read_32(offset); |
98 | tmp = ctrl_read_32(offset); |
98 | 99 | ||
99 | while (timeout) |
100 | while (timeout) |
100 | { |
101 | { |
101 | if (Operation==CLEAR){ |
102 | if (Operation==CLEAR){ |
102 | if (!(tmp & Bit)) |
103 | if (!(tmp & Bit)) |
103 | break; |
104 | break; |
104 | } else if (tmp & Bit) |
105 | } else if (tmp & Bit) |
105 | break; |
106 | break; |
106 | 107 | ||
107 | /*If the Bit is not clear yet, we wait for 10 milisecond and try again*/ |
108 | /*If the Bit is not clear yet, we wait for 10 milisecond and try again*/ |
108 | delay(10/10); |
109 | delay(10/10); |
109 | 110 | ||
110 | tmp = ctrl_read_32(offset); |
111 | tmp = ctrl_read_32(offset); |
111 | 112 | ||
112 | timeout--; |
113 | timeout--; |
113 | }; |
114 | }; |
114 | 115 | ||
115 | if (pReturnValue) |
116 | if (pReturnValue) |
116 | *pReturnValue=tmp; |
117 | *pReturnValue=tmp; |
117 | 118 | ||
118 | if (!timeout) |
119 | if (!timeout) |
119 | return FALSE; |
120 | return FALSE; |
120 | 121 | ||
121 | return TRUE; |
122 | return TRUE; |
122 | } |
123 | } |
123 | 124 | ||
124 | u16_t snd_hw_CodecRead ( u8_t CodecRegister ) |
125 | u16_t snd_hw_CodecRead ( u8_t CodecRegister ) |
125 | { |
126 | { |
126 | u32_t CodecRegister_data = 0; |
127 | u32_t CodecRegister_data = 0; |
127 | u32_t timeout=10; |
128 | u32_t timeout=10; |
128 | volatile u32_t val=0; |
129 | volatile u32_t val=0; |
129 | 130 | ||
130 | CodecRegister_data = ((u32_t)CodecRegister)<<24; |
131 | CodecRegister_data = ((u32_t)CodecRegister)<<24; |
131 | CodecRegister_data |= 0x80000000; /* High-bit set (p.106) is a CODEC reg READ.*/ |
132 | CodecRegister_data |= 0x80000000; /* High-bit set (p.106) is a CODEC reg READ.*/ |
132 | 133 | ||
133 | /* Set the bit. We are going to access the CODEC...*/ |
134 | /* Set the bit. We are going to access the CODEC...*/ |
134 | CodecRegister_data |= BIT_5535_CODEC_COMMAND_NEW; |
135 | CodecRegister_data |= BIT_5535_CODEC_COMMAND_NEW; |
135 | 136 | ||
136 | /*Request the data*/ |
137 | /*Request the data*/ |
137 | ctrl_write_32(CODEC_CONTROL_REG_5535, CodecRegister_data); |
138 | ctrl_write_32(CODEC_CONTROL_REG_5535, CodecRegister_data); |
138 | 139 | ||
139 | /* Now we need to wait for BIT_5535_CODEC_COMMAND_NEW of the Codec control register to clear |
140 | /* Now we need to wait for BIT_5535_CODEC_COMMAND_NEW of the Codec control register to clear |
140 | (For subsequent Reads/Writes)*/ |
141 | (For subsequent Reads/Writes)*/ |
141 | if (!snd_hw_WaitForBit (CODEC_CONTROL_REG_5535, |
142 | if (!snd_hw_WaitForBit (CODEC_CONTROL_REG_5535, |
142 | BIT_5535_CODEC_COMMAND_NEW, CLEAR, 50, NULL)) |
143 | BIT_5535_CODEC_COMMAND_NEW, CLEAR, 50, NULL)) |
143 | DBG("BIT_5535_CODEC_COMMAND_NEW did not clear!!\n"); |
144 | DBG("BIT_5535_CODEC_COMMAND_NEW did not clear!!\n"); |
144 | 145 | ||
145 | /* Wait for CODEC_STATUS_NEW and confirm the read of the requested register*/ |
146 | /* Wait for CODEC_STATUS_NEW and confirm the read of the requested register*/ |
146 | timeout = 50; |
147 | timeout = 50; |
147 | do |
148 | do |
148 | { |
149 | { |
149 | val = ctrl_read_32(CODEC_STATUS_REG_5535); |
150 | val = ctrl_read_32(CODEC_STATUS_REG_5535); |
150 | if ((val & BIT_5535_CODEC_STATUS_NEW) && |
151 | if ((val & BIT_5535_CODEC_STATUS_NEW) && |
151 | ((u32_t) CodecRegister == ((0xFF000000 & val)>>24))) |
152 | ((u32_t) CodecRegister == ((0xFF000000 & val)>>24))) |
152 | break; |
153 | break; |
153 | else |
154 | else |
154 | /*Wait for 10 miliseconds and try again*/ |
155 | /*Wait for 10 miliseconds and try again*/ |
155 | delay(10/10); |
156 | delay(10/10); |
156 | } while ( --timeout); |
157 | } while ( --timeout); |
157 | 158 | ||
158 | if (!timeout) |
159 | if (!timeout) |
159 | DBG("Could not read the CODEC!! Returning what we got.\n"); |
160 | DBG("Could not read the CODEC!! Returning what we got.\n"); |
160 | 161 | ||
161 | return( (u16_t)val ); |
162 | return( (u16_t)val ); |
162 | } |
163 | } |
163 | 164 | ||
164 | void snd_hw_CodecWrite( u8_t CodecRegister, u16_t CodecData ) |
165 | void snd_hw_CodecWrite( u8_t CodecRegister, u16_t CodecData ) |
165 | { |
166 | { |
166 | u32_t CodecRegister_data; |
167 | u32_t CodecRegister_data; |
167 | u32_t Temp, timeout; |
168 | u32_t Temp, timeout; |
168 | 169 | ||
169 | CodecRegister_data = ((u32_t) CodecRegister)<<24; |
170 | CodecRegister_data = ((u32_t) CodecRegister)<<24; |
170 | CodecRegister_data |= (u32_t) CodecData; |
171 | CodecRegister_data |= (u32_t) CodecData; |
171 | CodecRegister_data &= CODEC_COMMAND_MASK; |
172 | CodecRegister_data &= CODEC_COMMAND_MASK; |
172 | 173 | ||
173 | /*Set the bit. We are going to access the CODEC...*/ |
174 | /*Set the bit. We are going to access the CODEC...*/ |
174 | CodecRegister_data |= BIT_5535_CODEC_COMMAND_NEW; |
175 | CodecRegister_data |= BIT_5535_CODEC_COMMAND_NEW; |
175 | 176 | ||
176 | /*Write the data*/ |
177 | /*Write the data*/ |
177 | ctrl_write_32(CODEC_CONTROL_REG_5535, CodecRegister_data); |
178 | ctrl_write_32(CODEC_CONTROL_REG_5535, CodecRegister_data); |
178 | //OS_DbgMsg("Writing: %08X\n", CodecRegister_data); |
179 | //OS_DbgMsg("Writing: %08X\n", CodecRegister_data); |
179 | 180 | ||
180 | /*We need to wait for bit16 of the Codec control register to clear*/ |
181 | /*We need to wait for bit16 of the Codec control register to clear*/ |
181 | Temp = ctrl_read_32(CODEC_CONTROL_REG_5535); |
182 | Temp = ctrl_read_32(CODEC_CONTROL_REG_5535); |
182 | 183 | ||
183 | timeout = 50; |
184 | timeout = 50; |
184 | 185 | ||
185 | while ((Temp & BIT_5535_CODEC_COMMAND_NEW) && timeout-- ) |
186 | while ((Temp & BIT_5535_CODEC_COMMAND_NEW) && timeout-- ) |
186 | Temp = ctrl_read_32(CODEC_CONTROL_REG_5535); |
187 | Temp = ctrl_read_32(CODEC_CONTROL_REG_5535); |
187 | 188 | ||
188 | if (!timeout) |
189 | if (!timeout) |
189 | DBG("Could not Write the CODEC!!\n" |
190 | DBG("Could not Write the CODEC!!\n" |
190 | "BIT_5535_CODEC_COMMAND_NEW did not clear!\n"); |
191 | "BIT_5535_CODEC_COMMAND_NEW did not clear!\n"); |
191 | } |
192 | } |
192 | 193 | ||
193 | 194 | ||
194 | void snd_hw_SetCodecRate(u32_t SampleRate) |
195 | void snd_hw_SetCodecRate(u32_t SampleRate) |
195 | { |
196 | { |
196 | u16_t val; |
197 | u16_t val; |
197 | 198 | ||
198 | DBG("Rate: %d\n", SampleRate); |
199 | DBG("Rate: %d\n", SampleRate); |
199 | 200 | ||
200 | /*If Double-Rate is supported (Bit 2 on register 28h)...*/ |
201 | /*If Double-Rate is supported (Bit 2 on register 28h)...*/ |
201 | val=snd_hw_CodecRead(EXTENDED_AUDIO_ID); |
202 | val=snd_hw_CodecRead(EXTENDED_AUDIO_ID); |
202 | 203 | ||
203 | if (val & 0x02) |
204 | if (val & 0x02) |
204 | { |
205 | { |
205 | DBG("Codec supports Double rate.\n"); |
206 | DBG("Codec supports Double rate.\n"); |
206 | val=snd_hw_CodecRead(EXT_AUDIO_CTRL_STAT); |
207 | val=snd_hw_CodecRead(EXT_AUDIO_CTRL_STAT); |
207 | 208 | ||
208 | if (SampleRate>48000) |
209 | if (SampleRate>48000) |
209 | { |
210 | { |
210 | snd_hw_CodecWrite(EXT_AUDIO_CTRL_STAT, (u16_t) (val|0x0002)); |
211 | snd_hw_CodecWrite(EXT_AUDIO_CTRL_STAT, (u16_t) (val|0x0002)); |
211 | SampleRate/=2; |
212 | SampleRate/=2; |
212 | } |
213 | } |
213 | else |
214 | else |
214 | snd_hw_CodecWrite(EXT_AUDIO_CTRL_STAT, (u16_t) (val&0xFFFD)); |
215 | snd_hw_CodecWrite(EXT_AUDIO_CTRL_STAT, (u16_t) (val&0xFFFD)); |
215 | } |
216 | } |
216 | if (geode.fAD1819A) |
217 | if (geode.fAD1819A) |
217 | { |
218 | { |
218 | DBG("AD1819...\n"); |
219 | DBG("AD1819...\n"); |
219 | snd_hw_CodecWrite(AD1819A_PCM_SR0,(u16_t)SampleRate); |
220 | snd_hw_CodecWrite(AD1819A_PCM_SR0,(u16_t)SampleRate); |
220 | } |
221 | } |
221 | else |
222 | else |
222 | snd_hw_CodecWrite(PCM_FRONT_DAC_RATE,(u16_t)SampleRate); |
223 | snd_hw_CodecWrite(PCM_FRONT_DAC_RATE,(u16_t)SampleRate); |
223 | } |
224 | } |
224 | 225 | ||
225 | Bool init_device() |
226 | Bool init_device() |
226 | { |
227 | { |
227 | u32_t io_base = pciReadLong(geode.pciTag, 0x10); |
228 | u32_t io_base = pciReadLong(geode.pciTag, 0x10); |
228 | 229 | ||
229 | if( PCI_MAP_IS_IO(io_base)) |
230 | if( PCI_MAP_IS_IO(io_base)) |
230 | { |
231 | { |
231 | geode.is_iomapped = TRUE; |
232 | geode.is_iomapped = TRUE; |
232 | geode.F3BAR0 = PCIGETIO(io_base); |
233 | geode.F3BAR0 = PCIGETIO(io_base); |
233 | DBG("io mapped F3BAR0 %x\n", geode.F3BAR0); |
234 | DBG("io mapped F3BAR0 %x\n", geode.F3BAR0); |
234 | } |
235 | } |
235 | else if(PCI_MAP_IS_MEM(io_base)) |
236 | else if(PCI_MAP_IS_MEM(io_base)) |
236 | { |
237 | { |
237 | geode.is_iomapped = FALSE; |
238 | geode.is_iomapped = FALSE; |
238 | io_base = PCIGETMEMORY(io_base); |
239 | io_base = PCIGETMEMORY(io_base); |
239 | geode.F3BAR0 = MapIoMem(io_base, 128, PG_SW+PG_NOCACHE); |
240 | geode.F3BAR0 = MapIoMem(io_base, 128, PG_SW+PG_NOCACHE); |
240 | DBG("memory mapped F3BAR0 %x\n", geode.F3BAR0); |
241 | DBG("memory mapped F3BAR0 %x\n", geode.F3BAR0); |
241 | } |
242 | } |
242 | 243 | ||
243 | geode.buffer = KernelAlloc(64*1024); |
244 | geode.buffer = KernelAlloc(64*1024); |
244 | 245 | ||
245 | addr_t buffer = geode.buffer; |
246 | addr_t buffer = geode.buffer; |
246 | addr_t dma = GetPgAddr(geode.buffer); |
247 | addr_t dma = GetPgAddr(geode.buffer); |
247 | geode.buffer_dma = dma; |
248 | geode.buffer_dma = dma; |
248 | 249 | ||
249 | geode.prd_dma = (((addr_t)prd_tab) & 4095) + GetPgAddr((void*)prd_tab); |
250 | geode.prd_dma = (((addr_t)prd_tab) & 4095) + GetPgAddr((void*)prd_tab); |
250 | 251 | ||
251 | prd_tab[0].ulPhysAddr = dma; |
252 | prd_tab[0].ulPhysAddr = dma; |
252 | prd_tab[0].SizeFlags = 16384 | PRD_EOP_BIT ; |
253 | prd_tab[0].SizeFlags = 16384 | PRD_EOP_BIT ; |
253 | 254 | ||
254 | prd_tab[1].ulPhysAddr = dma + 16384; |
255 | prd_tab[1].ulPhysAddr = dma + 16384; |
255 | prd_tab[1].SizeFlags = 16384 | PRD_EOP_BIT ; |
256 | prd_tab[1].SizeFlags = 16384 | PRD_EOP_BIT ; |
256 | 257 | ||
257 | prd_tab[2].ulPhysAddr = dma + 16384*2; |
258 | prd_tab[2].ulPhysAddr = dma + 16384*2; |
258 | prd_tab[2].SizeFlags = 16384 | PRD_EOP_BIT ; |
259 | prd_tab[2].SizeFlags = 16384 | PRD_EOP_BIT ; |
259 | 260 | ||
260 | prd_tab[3].ulPhysAddr = dma + 16384*3; |
261 | prd_tab[3].ulPhysAddr = dma + 16384*3; |
261 | prd_tab[3].SizeFlags = 16384 | PRD_EOP_BIT ; |
262 | prd_tab[3].SizeFlags = 16384 | PRD_EOP_BIT ; |
262 | 263 | ||
263 | prd_tab[4].ulPhysAddr = geode.prd_dma; |
264 | prd_tab[4].ulPhysAddr = geode.prd_dma; |
264 | prd_tab[4].SizeFlags = PRD_JMP_BIT ; |
265 | prd_tab[4].SizeFlags = PRD_JMP_BIT ; |
265 | 266 | ||
266 | ctrl_write_32(0x24, geode.prd_dma); |
267 | ctrl_write_32(0x24, geode.prd_dma); |
267 | 268 | ||
268 | __clear((void*)buffer,64*1024); |
269 | __clear((void*)buffer,64*1024); |
269 | // u32_t tmp = ctrl_read_32(0x24); |
270 | // u32_t tmp = ctrl_read_32(0x24); |
270 | 271 | ||
271 | // dbgprintf("Create primary buffer at %x dma at %x\n", geode.buffer, dma ); |
272 | // dbgprintf("Create primary buffer at %x dma at %x\n", geode.buffer, dma ); |
272 | 273 | ||
273 | // dbgprintf("Set prd dma %x, read prd dma %x\n", geode.prd_dma, tmp); |
274 | // dbgprintf("Set prd dma %x, read prd dma %x\n", geode.prd_dma, tmp); |
274 | 275 | ||
275 | geode.irq_line = pciReadLong(geode.pciTag, 0x3C) & 0xFF; |
276 | geode.irq_line = pciReadLong(geode.pciTag, 0x3C) & 0xFF; |
276 | geode.irq_mask = ~(1< |
277 | geode.irq_mask = ~(1< |
277 | 278 | ||
278 | DBG("Irq line %d, mask %x\n", geode.irq_line, geode.irq_mask); |
279 | DBG("Irq line %d, mask %x\n", geode.irq_line, geode.irq_mask); |
279 | 280 | ||
280 | 281 | ||
281 | /* |
282 | /* |
282 | geode.CommandRegister = geode.F3BAR0+0x20; |
283 | geode.CommandRegister = geode.F3BAR0+0x20; |
283 | geode.PRDTableAddress = geode.F3BAR0+0x24; |
284 | geode.PRDTableAddress = geode.F3BAR0+0x24; |
284 | geode.DMAPointer = geode.F3BAR0+0x60; |
285 | geode.DMAPointer = geode.F3BAR0+0x60; |
285 | 286 | ||
286 | geode.IRQControlRegister = geode.F3BAR0+0x1C; |
287 | geode.IRQControlRegister = geode.F3BAR0+0x1C; |
287 | geode.InternalIRQEnableRegister = geode.F3BAR0+0x1A; |
288 | geode.InternalIRQEnableRegister = geode.F3BAR0+0x1A; |
288 | geode.SMI_StatusRegister = geode.F3BAR0+0x21; |
289 | geode.SMI_StatusRegister = geode.F3BAR0+0x21; |
289 | */ |
290 | */ |
290 | 291 | ||
291 | 292 | ||
292 | 293 | ||
293 | /*CODEC - RESET and volumes initalization.*/ |
294 | /*CODEC - RESET and volumes initalization.*/ |
294 | /*Set the Warm RESET and CODEC_COMMAND_NEW bits.*/ |
295 | /*Set the Warm RESET and CODEC_COMMAND_NEW bits.*/ |
295 | 296 | ||
296 | DBG("reset codec...\n"); |
297 | DBG("reset codec...\n"); |
297 | 298 | ||
298 | ctrl_write_32(CODEC_CONTROL_REG_5535, 0x00030000 ); |
299 | ctrl_write_32(CODEC_CONTROL_REG_5535, 0x00030000 ); |
299 | 300 | ||
300 | if (!snd_hw_WaitForBit (CODEC_STATUS_REG_5535, BIT_CODEC_READY, SET, 40, NULL)) |
301 | if (!snd_hw_WaitForBit (CODEC_STATUS_REG_5535, BIT_CODEC_READY, SET, 40, NULL)) |
301 | { |
302 | { |
302 | DBG("Primary Codec NOT Ready...Aborting\n"); |
303 | DBG("Primary Codec NOT Ready...Aborting\n"); |
303 | return FALSE; |
304 | return FALSE; |
304 | } |
305 | } |
305 | 306 | ||
306 | u16_t id7c, id7e; |
307 | u16_t id7c, id7e; |
307 | 308 | ||
308 | id7c = snd_hw_CodecRead(AD1819A_VENDORID1); |
309 | id7c = snd_hw_CodecRead(AD1819A_VENDORID1); |
309 | id7e = snd_hw_CodecRead(AD1819A_VENDORID2); |
310 | id7e = snd_hw_CodecRead(AD1819A_VENDORID2); |
310 | 311 | ||
311 | dbgprintf("codec id 0x7C %x 0x7E %x\n", id7c, id7e); |
312 | dbgprintf("codec id 0x7C %x 0x7E %x\n", id7c, id7e); |
312 | 313 | ||
313 | /*Check which codec is being used */ |
314 | /*Check which codec is being used */ |
314 | if ( (id7c == 0x4144) && |
315 | if ( (id7c == 0x4144) && |
315 | (id7e == 0x5303) ) |
316 | (id7e == 0x5303) ) |
316 | { |
317 | { |
317 | geode.fAD1819A = TRUE; |
318 | geode.fAD1819A = TRUE; |
318 | /* Enable non-48kHz sample rates. */ |
319 | /* Enable non-48kHz sample rates. */ |
319 | snd_hw_CodecWrite (AD1819A_SER_CONF, |
320 | snd_hw_CodecWrite (AD1819A_SER_CONF, |
320 | snd_hw_CodecRead(AD1819A_SER_CONF>>8) | |
321 | snd_hw_CodecRead(AD1819A_SER_CONF>>8) | |
321 | AD1819A_SER_CONF_DRQEN); |
322 | AD1819A_SER_CONF_DRQEN); |
322 | DBG("detect AD1819A audio codec\n"); |
323 | DBG("detect AD1819A audio codec\n"); |
323 | } |
324 | } |
324 | else |
325 | else |
325 | { |
326 | { |
326 | geode.fAD1819A = FALSE; |
327 | geode.fAD1819A = FALSE; |
327 | snd_hw_CodecWrite(EXT_AUDIO_CTRL_STAT, |
328 | snd_hw_CodecWrite(EXT_AUDIO_CTRL_STAT, |
328 | (snd_hw_CodecRead(EXT_AUDIO_CTRL_STAT) | 0x0001)); |
329 | (snd_hw_CodecRead(EXT_AUDIO_CTRL_STAT) | 0x0001)); |
329 | /* set the VRA bit to ON*/ |
330 | /* set the VRA bit to ON*/ |
330 | } |
331 | } |
331 | 332 | ||
332 | /* set default volume*/ |
333 | /* set default volume*/ |
333 | snd_hw_CodecWrite( MASTER_VOLUME, 0x0909); |
334 | snd_hw_CodecWrite( MASTER_VOLUME, 0x0909); |
334 | snd_hw_CodecWrite( PCM_OUT_VOL, 0x0606); |
335 | snd_hw_CodecWrite( PCM_OUT_VOL, 0x0606); |
335 | snd_hw_CodecWrite( PC_BEEP_VOLUME, 0x0000); |
336 | snd_hw_CodecWrite( PC_BEEP_VOLUME, 0x0000); |
336 | snd_hw_CodecWrite( PHONE_VOLUME, 0x0606); |
337 | snd_hw_CodecWrite( PHONE_VOLUME, 0x0606); |
337 | snd_hw_CodecWrite( MIC_VOLUME, 0x8048); |
338 | snd_hw_CodecWrite( MIC_VOLUME, 0x8048); |
338 | snd_hw_CodecWrite( LINE_IN_VOLUME, 0x0808); |
339 | snd_hw_CodecWrite( LINE_IN_VOLUME, 0x0808); |
339 | snd_hw_CodecWrite( CD_VOLUME, 0x8000); |
340 | snd_hw_CodecWrite( CD_VOLUME, 0x8000); |
340 | snd_hw_CodecWrite( VIDEO_VOLUME, 0x8000); |
341 | snd_hw_CodecWrite( VIDEO_VOLUME, 0x8000); |
341 | snd_hw_CodecWrite( TV_VOLUME, 0x8000); |
342 | snd_hw_CodecWrite( TV_VOLUME, 0x8000); |
342 | snd_hw_CodecWrite( RECORD_SELECT, 0x0000); |
343 | snd_hw_CodecWrite( RECORD_SELECT, 0x0000); |
343 | snd_hw_CodecWrite( RECORD_GAIN, 0x0a0a); |
344 | snd_hw_CodecWrite( RECORD_GAIN, 0x0a0a); |
344 | snd_hw_CodecWrite( GENERAL_PURPOSE, 0x0200); |
345 | snd_hw_CodecWrite( GENERAL_PURPOSE, 0x0200); |
345 | snd_hw_CodecWrite( MASTER_VOLUME_MONO, 0x0000); |
346 | snd_hw_CodecWrite( MASTER_VOLUME_MONO, 0x0000); |
346 | 347 | ||
347 | snd_hw_SetCodecRate(48000); |
348 | snd_hw_SetCodecRate(48000); |
348 | /*Set all the power state bits to 0 (Reg 26h)*/ |
349 | /*Set all the power state bits to 0 (Reg 26h)*/ |
349 | snd_hw_CodecWrite (POWERDOWN_CTRL_STAT, 0x0000); |
350 | snd_hw_CodecWrite (POWERDOWN_CTRL_STAT, 0x0000); |
350 | geode.CurrentPowerState = GEODEAUDIO_D0; |
351 | geode.CurrentPowerState = GEODEAUDIO_D0; |
351 | // OS_DbgMsg("<--snd_hw_InitAudioRegs\n"); |
352 | // OS_DbgMsg("<--snd_hw_InitAudioRegs\n"); |
352 | 353 | ||
353 | 354 | ||
354 | return TRUE; |
355 | return TRUE; |
355 | } |
356 | } |
356 | 357 | ||
357 | static int snd_StartDMA () |
358 | static int snd_StartDMA () |
358 | { |
359 | { |
359 | 360 | ||
360 | #ifdef FORCED_PIO |
361 | #ifdef FORCED_PIO |
361 | out8( (u16_t)(geode.F3BAR0+0x20),PCI_READS | ENABLE_BUSMASTER); |
362 | out8( (u16_t)(geode.F3BAR0+0x20),PCI_READS | ENABLE_BUSMASTER); |
362 | #else |
363 | #else |
363 | if (geode.is_iomapped) |
364 | if (geode.is_iomapped) |
364 | out8( (u16_t)(geode.F3BAR0+0x20),PCI_READS | ENABLE_BUSMASTER); |
365 | out8( (u16_t)(geode.F3BAR0+0x20),PCI_READS | ENABLE_BUSMASTER); |
365 | else |
366 | else |
366 | *(u8_t*)(geode.F3BAR0+0x20)= PCI_READS | ENABLE_BUSMASTER; |
367 | *(u8_t*)(geode.F3BAR0+0x20)= PCI_READS | ENABLE_BUSMASTER; |
367 | #endif |
368 | #endif |
368 | return 0; |
369 | return 0; |
369 | }; |
370 | }; |
370 | 371 | ||
371 | static u8_t snd_hw_InterruptID () |
372 | static u8_t snd_hw_InterruptID () |
372 | { |
373 | { |
373 | volatile u8_t *TempInterruptID, ID; |
374 | volatile u8_t *TempInterruptID, ID; |
374 | 375 | ||
375 | #ifdef FORCED_PIO |
376 | #ifdef FORCED_PIO |
376 | ID=(u8_t) in16((u16_t)(geode.F3BAR0 + 0x12)); |
377 | ID=(u8_t) in16((u16_t)(geode.F3BAR0 + 0x12)); |
377 | #else |
378 | #else |
378 | if (geode.is_iomapped) |
379 | if (geode.is_iomapped) |
379 | ID=(u8_t) in16((u16_t)(geode.F3BAR0 + 0x12)); |
380 | ID=(u8_t) in16((u16_t)(geode.F3BAR0 + 0x12)); |
380 | else |
381 | else |
381 | { |
382 | { |
382 | TempInterruptID=(u8_t*)(geode.F3BAR0 + 0x12); |
383 | TempInterruptID=(u8_t*)(geode.F3BAR0 + 0x12); |
383 | ID=*TempInterruptID; |
384 | ID=*TempInterruptID; |
384 | } |
385 | } |
385 | #endif |
386 | #endif |
386 | return (ID); |
387 | return (ID); |
387 | } |
388 | } |
388 | 389 | ||
389 | 390 | ||
390 | static u8_t snd_hw_ClearStat(int Channel) |
391 | static u8_t snd_hw_ClearStat(int Channel) |
391 | { |
392 | { |
392 | volatile u8_t status; /*Volatile to force read-to-clear.*/ |
393 | volatile u8_t status; /*Volatile to force read-to-clear.*/ |
393 | 394 | ||
394 | /*Read to clear*/ |
395 | /*Read to clear*/ |
395 | 396 | ||
396 | #ifdef FORCED_PIO |
397 | #ifdef FORCED_PIO |
397 | status = in8((u16_t) geode.F3BAR0 + 0x21); |
398 | status = in8((u16_t) geode.F3BAR0 + 0x21); |
398 | #else |
399 | #else |
399 | if (geode.is_iomapped) |
400 | if (geode.is_iomapped) |
400 | status = in8((u16_t) geode.F3BAR0 + 0x21); |
401 | status = in8((u16_t) geode.F3BAR0 + 0x21); |
401 | else |
402 | else |
402 | status = *((u8_t*)geode.F3BAR0 + 0x21); |
403 | status = *((u8_t*)geode.F3BAR0 + 0x21); |
403 | #endif |
404 | #endif |
404 | return status; |
405 | return status; |
405 | } |
406 | } |
406 | 407 | ||
407 | 408 | ||
408 | void snd_interrupt() |
409 | void snd_interrupt() |
409 | { |
410 | { |
410 | u8_t IntID; |
411 | u8_t IntID; |
411 | 412 | ||
412 | IntID = snd_hw_InterruptID(); |
413 | IntID = snd_hw_InterruptID(); |
413 | 414 | ||
414 | // dbgprintf("IRQ id %x\n", IntID); |
415 | // dbgprintf("IRQ id %x\n", IntID); |
415 | 416 | ||
416 | snd_hw_ClearStat(CHANNEL0_PLAYBACK); |
417 | snd_hw_ClearStat(CHANNEL0_PLAYBACK); |
417 | // snd_hw_ClearStat(CHANNEL1_RECORD); |
418 | // snd_hw_ClearStat(CHANNEL1_RECORD); |
418 | 419 | ||
419 | if(IntID & BM0_IRQ) |
420 | if(IntID & BM0_IRQ) |
420 | { |
421 | { |
421 | addr_t prd, offset, base; |
422 | addr_t prd, offset, base; |
422 | 423 | ||
423 | prd = ctrl_read_32(0x24); |
424 | prd = ctrl_read_32(0x24); |
424 | offset = (1 + (prd - geode.prd_dma)>>3) & 3; |
425 | offset = (1 + (prd - geode.prd_dma)>>3) & 3; |
425 | 426 | ||
426 | base = geode.buffer + 16384*offset; |
427 | base = geode.buffer + 16384*offset; |
427 | 428 | ||
428 | geode.callback(base); |
429 | geode.callback(base); |
429 | __asm__ volatile("":::"ebx","esi","edi"); |
430 | __asm__ volatile("":::"ebx","esi","edi"); |
430 | 431 | ||
431 | // dbgprintf(">>BM0_IRQ prd %x offset %x base %x\n", prd, offset, base); |
432 | // dbgprintf(">>BM0_IRQ prd %x offset %x base %x\n", prd, offset, base); |
432 | }; |
433 | }; |
433 | }; |
434 | }; |
434 | 435 | ||
435 | Bool FindPciDevice() |
436 | Bool FindPciDevice() |
436 | { |
437 | { |
437 | u32_t bus, last_bus; |
438 | u32_t bus, last_bus; |
438 | PCITAG tag; |
439 | PCITAG tag; |
439 | 440 | ||
440 | if( (last_bus = PciApi(1))==-1) |
441 | if( (last_bus = PciApi(1))==-1) |
441 | return FALSE; |
442 | return FALSE; |
442 | 443 | ||
443 | for(bus=0;bus<=last_bus;bus++) |
444 | for(bus=0;bus<=last_bus;bus++) |
444 | { |
445 | { |
445 | u32_t devfn; |
446 | u32_t devfn; |
446 | 447 | ||
447 | for(devfn=0;devfn<256;devfn++) |
448 | for(devfn=0;devfn<256;devfn++) |
448 | { |
449 | { |
449 | u32_t pciId=0; |
450 | u32_t pciId=0; |
450 | 451 | ||
451 | pciId = PciRead32(bus,devfn, 0); |
452 | pciId = PciRead32(bus,devfn, 0); |
452 | 453 | ||
453 | if( (pciId == ID_DEV_1) || |
454 | if( (pciId == ID_DEV_1) || |
454 | (pciId == ID_DEV_2) ) |
455 | (pciId == ID_DEV_2) ) |
455 | { |
456 | { |
456 | DBG("detect companion audio device %x\n", pciId); |
457 | DBG("detect companion audio device %x\n", pciId); |
457 | geode.pciTag = pciTag(bus,(devfn>>3)&0x1F,devfn&0x7); |
458 | geode.pciTag = pciTag(bus,(devfn>>3)&0x1F,devfn&0x7); |
458 | return TRUE; |
459 | return TRUE; |
459 | }; |
460 | }; |
460 | }; |
461 | }; |
461 | }; |
462 | }; |
462 | return FALSE; |
463 | return FALSE; |
463 | }; |
464 | }; |
464 | 465 | ||
465 | 466 | ||
466 | u32_t drvEntry(int action, char *cmdline) |
467 | u32_t drvEntry(int action, char *cmdline) |
467 | { |
468 | { |
468 | u32_t retval; |
469 | u32_t retval; |
469 | 470 | ||
470 | int i; |
471 | int i; |
471 | 472 | ||
472 | if(action != 1) |
473 | if(action != 1) |
473 | return 0; |
474 | return 0; |
474 | 475 | ||
475 | if(!dbg_open("/rd/1/drivers/geode.log")) |
476 | if(!dbg_open("/rd/1/drivers/geode.log")) |
476 | { |
477 | { |
477 | printf("Can't open /rd/1/drivers/geode.log\nExit\n"); |
478 | printf("Can't open /rd/1/drivers/geode.log\nExit\n"); |
478 | return 0; |
479 | return 0; |
479 | } |
480 | } |
480 | 481 | ||
481 | printf("AMD Geode CS5536 audio driver\n"); |
482 | printf("AMD Geode CS5536 audio driver\n"); |
482 | 483 | ||
483 | if( FindPciDevice() == FALSE) |
484 | if( FindPciDevice() == FALSE) |
484 | { |
485 | { |
485 | dbgprintf("Device not found\n"); |
486 | dbgprintf("Device not found\n"); |
486 | return 0; |
487 | return 0; |
487 | }; |
488 | }; |
488 | 489 | ||
489 | init_device(); |
490 | init_device(); |
490 | 491 | ||
491 | retval = RegService("SOUND", srv_sound); |
492 | retval = RegService("SOUND", srv_sound); |
492 | 493 | ||
493 | AttachIntHandler(geode.irq_line, snd_interrupt, 0); |
494 | AttachIntHandler(geode.irq_line, snd_interrupt, 0); |
494 | 495 | ||
495 | DBG("reg service %s as: %x\n", "SOUND", retval); |
496 | DBG("reg service %s as: %x\n", "SOUND", retval); |
496 | 497 | ||
497 | return retval; |
498 | return retval; |
498 | }; |
499 | }; |
499 | 500 | ||
500 | 501 | ||
501 | #define API_VERSION 0x01000100 |
502 | #define API_VERSION 0x01000100 |
502 | 503 | ||
503 | #define SRV_GETVERSION 0 |
504 | #define SRV_GETVERSION 0 |
504 | #define DEV_PLAY 1 |
505 | #define DEV_PLAY 1 |
505 | #define DEV_STOP 2 |
506 | #define DEV_STOP 2 |
506 | #define DEV_CALLBACK 3 |
507 | #define DEV_CALLBACK 3 |
507 | #define DEV_SET_BUFF 4 |
508 | #define DEV_SET_BUFF 4 |
508 | #define DEV_NOTIFY 5 |
509 | #define DEV_NOTIFY 5 |
509 | #define DEV_SET_MASTERVOL 6 |
510 | #define DEV_SET_MASTERVOL 6 |
510 | #define DEV_GET_MASTERVOL 7 |
511 | #define DEV_GET_MASTERVOL 7 |
511 | #define DEV_GET_INFO 8 |
512 | #define DEV_GET_INFO 8 |
512 | #define DEV_GET_POS 9 |
513 | #define DEV_GET_POS 9 |
513 | 514 | ||
514 | int __stdcall srv_sound(ioctl_t *io) |
515 | int __stdcall srv_sound(ioctl_t *io) |
515 | { |
516 | { |
516 | u32_t *inp; |
517 | u32_t *inp; |
517 | u32_t *outp; |
518 | u32_t *outp; |
518 | 519 | ||
519 | inp = io->input; |
520 | inp = io->input; |
520 | outp = io->output; |
521 | outp = io->output; |
521 | 522 | ||
522 | switch(io->io_code) |
523 | switch(io->io_code) |
523 | { |
524 | { |
524 | case SRV_GETVERSION: |
525 | case SRV_GETVERSION: |
525 | if(io->out_size==4) |
526 | if(io->out_size==4) |
526 | { |
527 | { |
527 | *outp = API_VERSION; |
528 | *outp = API_VERSION; |
528 | return 0; |
529 | return 0; |
529 | } |
530 | } |
530 | break; |
531 | break; |
531 | 532 | ||
532 | case DEV_PLAY: |
533 | case DEV_PLAY: |
533 | return snd_StartDMA(); |
534 | return snd_StartDMA(); |
534 | break; |
535 | break; |
535 | 536 | ||
536 | case DEV_STOP: |
537 | case DEV_STOP: |
537 | break; |
538 | break; |
538 | 539 | ||
539 | case DEV_CALLBACK: |
540 | case DEV_CALLBACK: |
540 | if(io->inp_size==4) |
541 | if(io->inp_size==4) |
541 | { |
542 | { |
542 | geode.callback = (void*)(*inp); |
543 | geode.callback = (void*)(*inp); |
543 | return 0; |
544 | return 0; |
544 | } |
545 | } |
545 | break; |
546 | break; |
546 | 547 | ||
547 | case DEV_GET_POS: |
548 | case DEV_GET_POS: |
548 | if(io->out_size==4) |
549 | if(io->out_size==4) |
549 | { |
550 | { |
550 | u32_t dma; |
551 | u32_t dma; |
551 | dma = ctrl_read_32(0x60); |
552 | dma = ctrl_read_32(0x60); |
552 | dma-= geode.buffer_dma; |
553 | dma-= geode.buffer_dma; |
553 | *outp = (dma & 16383)>>2; |
554 | *outp = (dma & 16383)>>2; |
554 | return 0; |
555 | return 0; |
555 | } |
556 | } |
556 | break; |
557 | break; |
557 | 558 | ||
558 | default: |
559 | default: |
559 | return ERR_PARAM; |
560 | return ERR_PARAM; |
560 | }; |
561 | }; |
561 | return ERR_PARAM; |
562 | return ERR_PARAM; |
562 | }256;devfn++) |
563 | }256;devfn++) |
563 | >=last_bus;bus++) |
564 | >=last_bus;bus++) |
564 | >--snd_hw_InitAudioRegs\n"); |
565 | >--snd_hw_InitAudioRegs\n"); |
565 | 566 | ||
566 | 567 | ||
567 | > |
568 | > |
568 | 569 | ||
569 | > |
570 | > |
570 | 571 | ||
571 | >24; |
572 | >24; |
572 | ><24; |
573 | ><24; |
573 | >24; |
574 | >24; |
574 | ><24; |
575 | ><24; |
575 | >><>><>><> |
576 | >><>><>><> |