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