xref: /haiku/src/add-ons/kernel/drivers/audio/emuxki/io.c (revision 21258e2674226d6aa732321b6f8494841895af5f)
1 /*
2  * Emuxki BeOS Driver for Creative Labs SBLive!/Audigy series
3  *
4  * Copyright (c) 2002, Jerome Duval (jerome.duval@free.fr)
5  *
6  * Original code : BeOS Driver for Intel ICH AC'97 Link interface
7  * Copyright (c) 2002, Marcus Overhagen <marcus@overhagen.de>
8  *
9  * All rights reserved.
10  * Redistribution and use in source and binary forms, with or without modification,
11  * are permitted provided that the following conditions are met:
12  *
13  * - Redistributions of source code must retain the above copyright notice,
14  *   this list of conditions and the following disclaimer.
15  * - Redistributions in binary form must reproduce the above copyright notice,
16  *   this list of conditions and the following disclaimer in the documentation
17  *   and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
25  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  */
31 #include <KernelExport.h>
32 #include <OS.h>
33 #include <PCI.h>
34 #include "io.h"
35 #include "emuxkireg.h"
36 
37 extern pci_module_info *pci;
38 
39 uint8
40 emuxki_reg_read_8(device_config *config, int regno)
41 {
42 	return pci->read_io_8(config->nabmbar + regno);
43 }
44 
45 uint16
46 emuxki_reg_read_16(device_config *config, int regno)
47 {
48 	return pci->read_io_16(config->nabmbar + regno);
49 }
50 
51 uint32
52 emuxki_reg_read_32(device_config *config, int regno)
53 {
54 	return pci->read_io_32(config->nabmbar + regno);
55 }
56 
57 void
58 emuxki_reg_write_8(device_config *config, int regno, uint8 value)
59 {
60 	pci->write_io_8(config->nabmbar + regno, value);
61 }
62 
63 void
64 emuxki_reg_write_16(device_config *config, int regno, uint16 value)
65 {
66 	pci->write_io_16(config->nabmbar + regno, value);
67 }
68 
69 void
70 emuxki_reg_write_32(device_config *config, int regno, uint32 value)
71 {
72 	pci->write_io_32(config->nabmbar + regno, value);
73 }
74 
75 /* Emu10k1 Low level */
76 
77 uint32
78 emuxki_chan_read(device_config *config, uint16 chano, uint32 reg)
79 {
80 	uint32       ptr, mask = 0xFFFFFFFF;
81 	uint8        size, offset = 0;
82 
83 	ptr = ((((uint32) reg) << 16) &
84 		(IS_AUDIGY(config) ? EMU_A_PTR_ADDR_MASK : EMU_PTR_ADDR_MASK)) |
85 		(chano & EMU_PTR_CHNO_MASK);
86 	if (reg & 0xff000000) {
87 		size = (reg >> 24) & 0x3f;
88 		offset = (reg >> 16) & 0x1f;
89 		mask = ((1 << size) - 1) << offset;
90 	}
91 	pci->write_io_32(config->nabmbar + EMU_PTR, ptr);
92 	ptr = (pci->read_io_32(config->nabmbar + EMU_DATA) & mask) >> offset;
93 	return ptr;
94 }
95 
96 void
97 emuxki_chan_write(device_config *config, uint16 chano,
98 	      uint32 reg, uint32 data)
99 {
100 	uint32       ptr, mask;
101 	uint8        size, offset;
102 
103 	ptr = ((((uint32) reg) << 16) &
104 		(IS_AUDIGY(config) ? EMU_A_PTR_ADDR_MASK : EMU_PTR_ADDR_MASK)) |
105 		(chano & EMU_PTR_CHNO_MASK);
106 	if (reg & 0xff000000) {
107 		size = (reg >> 24) & 0x3f;
108 		offset = (reg >> 16) & 0x1f;
109 		mask = ((1 << size) - 1) << offset;
110 		data = ((data << offset) & mask) |
111 			(emuxki_chan_read(config, chano, reg & 0xFFFF) & ~mask);
112 	}
113 	pci->write_io_32(config->nabmbar + EMU_PTR, ptr);
114 	pci->write_io_32(config->nabmbar + EMU_DATA, data);
115 }
116 
117 /* Microcode */
118 
119 static void
120 emuxki_write_micro(device_config *config, uint32 pc, uint32 data)
121 {
122 	emuxki_chan_write(config, 0, (IS_AUDIGY(config) ? EMU_A_MICROCODEBASE :
123 		EMU_MICROCODEBASE ) + pc, data);
124 }
125 
126 static uint32
127 emuxki_read_micro(device_config *config, uint32 pc)
128 {
129 	return emuxki_chan_read(config, 0, (IS_AUDIGY(config) ? EMU_A_MICROCODEBASE :
130 		EMU_MICROCODEBASE ) + pc);
131 }
132 
133 void
134 emuxki_dsp_addop(device_config *config, uint16 *pc, uint8 op,
135 		  uint16 r, uint16 a, uint16 x, uint16 y)
136 {
137 	if(IS_AUDIGY(config)) {
138 		emuxki_write_micro(config, *pc << 1,
139 			    ((x << 12) & EMU_A_DSP_LOWORD_OPX_MASK) |
140 			    (y & EMU_A_DSP_LOWORD_OPY_MASK));
141 		emuxki_write_micro(config, (*pc << 1) + 1,
142 			    ((op << 24) & EMU_A_DSP_HIWORD_OPCODE_MASK) |
143 			    ((r << 12) & EMU_A_DSP_HIWORD_RESULT_MASK) |
144 			    (a & EMU_A_DSP_HIWORD_OPA_MASK));
145 	} else {
146 		emuxki_write_micro(config, *pc << 1,
147 			    ((x << 10) & EMU_DSP_LOWORD_OPX_MASK) |
148 			    (y & EMU_DSP_LOWORD_OPY_MASK));
149 		emuxki_write_micro(config, (*pc << 1) + 1,
150 			    ((op << 20) & EMU_DSP_HIWORD_OPCODE_MASK) |
151 			    ((r << 10) & EMU_DSP_HIWORD_RESULT_MASK) |
152 			    (a & EMU_DSP_HIWORD_OPA_MASK));
153 	}
154 	(*pc)++;
155 }
156 
157 void
158 emuxki_dsp_getop(device_config *config, uint16 *pc, uint8 *op,
159 		  uint16 *r, uint16 *a, uint16 *x, uint16 *y)
160 {
161 	uint32 value;
162 	if(IS_AUDIGY(config)) {
163 		value = emuxki_read_micro(config, *pc << 1);
164 		*x = (value & EMU_A_DSP_LOWORD_OPX_MASK) >> 12;
165 		*y = value & EMU_A_DSP_LOWORD_OPY_MASK;
166 		value = emuxki_read_micro(config, (*pc << 1) + 1);
167 		*op = (value & EMU_A_DSP_HIWORD_OPCODE_MASK) >> 24;
168 		*r = (value & EMU_A_DSP_HIWORD_RESULT_MASK) >> 12;
169 		*a = value & EMU_A_DSP_HIWORD_OPA_MASK;
170 	} else {
171 		value = emuxki_read_micro(config, *pc << 1);
172 		*x = (value & EMU_DSP_LOWORD_OPX_MASK) >> 10;
173 		*y = value & EMU_DSP_LOWORD_OPY_MASK;
174 		value = emuxki_read_micro(config, (*pc << 1) + 1);
175 		*op = (value & EMU_DSP_HIWORD_OPCODE_MASK) >> 20;
176 		*r = (value & EMU_DSP_HIWORD_RESULT_MASK) >> 10;
177 		*a = value & EMU_DSP_HIWORD_OPA_MASK;
178 	}
179 	(*pc)++;
180 }
181 
182 /* Gpr */
183 
184 void
185 emuxki_write_gpr(device_config *config, uint32 pc, uint32 data)
186 {
187 	emuxki_chan_write(config, 0, IS_AUDIGY(config) ? EMU_A_DSP_GPR(pc) :
188 		EMU_DSP_GPR(pc), data);
189 }
190 
191 uint32
192 emuxki_read_gpr(device_config *config, uint32 pc)
193 {
194 	return emuxki_chan_read(config, 0, IS_AUDIGY(config) ? EMU_A_DSP_GPR(pc) :
195 		EMU_DSP_GPR(pc));
196 }
197 
198 /* codec */
199 
200 uint16
201 emuxki_codec_read(device_config *config, int regno)
202 {
203 	pci->write_io_8(config->nabmbar + EMU_AC97ADDR, regno);
204 	return pci->read_io_16(config->nabmbar + EMU_AC97DATA);
205 }
206 
207 void
208 emuxki_codec_write(device_config *config, int regno, uint16 value)
209 {
210 	pci->write_io_8(config->nabmbar + EMU_AC97ADDR, regno);
211 	pci->write_io_16(config->nabmbar + EMU_AC97DATA, value);
212 }
213 
214 /* inte */
215 
216 void
217 emuxki_inte_enable(device_config *config, uint32 value)
218 {
219 	emuxki_reg_write_32(config, EMU_INTE,
220 		emuxki_reg_read_32(config, EMU_INTE) | value);
221 }
222 
223 void
224 emuxki_inte_disable(device_config *config, uint32 value)
225 {
226 	emuxki_reg_write_32(config, EMU_INTE,
227 		emuxki_reg_read_32(config, EMU_INTE) & ~value);
228 }
229 
230 /* p16v */
231 uint32
232 emuxki_p16v_read(device_config *config, uint16 chano, uint16 reg)
233 {
234 	emuxki_reg_write_32(config, EMU_A2_PTR, reg << 16 | chano);
235 	return emuxki_reg_read_32(config, EMU_A2_DATA);
236 }
237 
238 
239 void
240 emuxki_p16v_write(device_config *config, uint16 chano, uint16 reg, uint32 data)
241 {
242 	emuxki_reg_write_32(config, EMU_A2_PTR, reg << 16 | chano);
243 	emuxki_reg_write_32(config, EMU_A2_DATA, data);
244 }
245