1 /* $NetBSD: hdaudiovar.h,v 1.8 2019/07/25 00:30:45 jmcneill Exp $ */
2
3 /*
4 * Copyright (c) 2009 Precedence Technologies Ltd <support@precedence.co.uk>
5 * Copyright (c) 2009 Jared D. McNeill <jmcneill@invisible.ca>
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Precedence Technologies Ltd
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #ifndef _HDAUDIOVAR_H
33 #define _HDAUDIOVAR_H
34
35 #include <dev/audio/audio_if.h>
36
37 #ifdef _KERNEL_OPT
38 #include "opt_hdaudio.h"
39 #endif
40
41 #define HDAUDIO_MAX_CODECS 15
42
43 #define hda_print(sc, ...) \
44 aprint_normal_dev((sc)->sc_dev, __VA_ARGS__)
45 #define hda_print1(sc, ...) \
46 aprint_normal(__VA_ARGS__)
47 #define hda_error(sc, ...) \
48 aprint_error_dev((sc)->sc_dev, __VA_ARGS__)
49 #ifdef HDAUDIO_DEBUG
50 #define hda_trace(sc, ...) \
51 aprint_normal_dev((sc)->sc_dev, __VA_ARGS__)
52 #define hda_trace1(sc, ...) \
53 aprint_normal(__VA_ARGS__)
54 #else
55 #define hda_trace(sc, ...) do { } while (0)
56 #define hda_trace1(sc, ...) do { } while (0)
57 #endif
58 #define hda_delay(us) \
59 delay((us))
60
61 enum function_group_type {
62 HDAUDIO_GROUP_TYPE_UNKNOWN = 0,
63 HDAUDIO_GROUP_TYPE_AFG,
64 HDAUDIO_GROUP_TYPE_VSM_FG,
65 };
66
67 struct hdaudio_softc;
68
69 struct hdaudio_function_group {
70 device_t fg_device;
71 struct hdaudio_codec *fg_codec;
72 enum function_group_type fg_type;
73 int fg_nid;
74 uint16_t fg_vendor;
75 uint16_t fg_product;
76
77 int (*fg_unsol)(device_t, uint8_t);
78 };
79
80 struct hdaudio_codec {
81 bool co_valid;
82 u_int co_addr;
83 u_int co_nfg;
84 struct hdaudio_function_group *co_fg;
85 struct hdaudio_softc *co_host;
86 };
87
88 #define DMA_KERNADDR(dma) ((dma)->dma_addr)
89 #define DMA_DMAADDR(dma) ((dma)->dma_map->dm_segs[0].ds_addr)
90
91 struct hdaudio_dma {
92 bus_dmamap_t dma_map;
93 void *dma_addr;
94 bus_dma_segment_t dma_segs[1];
95 int dma_nsegs;
96 bus_size_t dma_size;
97 bool dma_valid;
98 uint8_t dma_sizereg;
99 };
100
101 #define HDAUDIO_MAX_STREAMS 30
102
103 struct hdaudio_dma_position {
104 uint32_t position;
105 uint32_t reserved;
106 } __packed;
107
108 struct hdaudio_bdl_entry {
109 uint32_t address_lo;
110 uint32_t address_hi;
111 uint32_t length;
112 uint32_t flags;
113 #define HDAUDIO_BDL_ENTRY_IOC 0x00000001
114 } __packed;
115
116 #define HDAUDIO_BDL_MAX 256
117
118 enum hdaudio_stream_type {
119 HDAUDIO_STREAM_ISS = 0,
120 HDAUDIO_STREAM_OSS = 1,
121 HDAUDIO_STREAM_BSS = 2
122 };
123
124 struct hdaudio_stream {
125 struct hdaudio_softc *st_host;
126 bool st_enable;
127 enum hdaudio_stream_type st_type;
128 int st_shift;
129 int st_num;
130
131 int (*st_intr)(struct hdaudio_stream *);
132 void *st_cookie;
133
134 struct hdaudio_dma st_data;
135 struct hdaudio_dma st_bdl;
136 };
137
138 struct hdaudio_softc {
139 device_t sc_dev;
140
141 bus_dma_tag_t sc_dmat;
142 bus_space_tag_t sc_memt;
143 bus_space_handle_t sc_memh;
144 bus_addr_t sc_membase;
145 bus_size_t sc_memsize;
146 bool sc_memvalid;
147
148 uint32_t sc_flags;
149 #define HDAUDIO_FLAG_32BIT __BIT(0)
150
151 uint32_t sc_subsystem;
152
153 kmutex_t sc_corb_mtx;
154 struct hdaudio_dma sc_corb;
155 struct hdaudio_dma sc_rirb;
156 uint16_t sc_rirbrp;
157
158 struct hdaudio_codec sc_codec[HDAUDIO_MAX_CODECS];
159
160 struct hdaudio_stream sc_stream[HDAUDIO_MAX_STREAMS];
161 uint32_t sc_stream_mask;
162 kmutex_t sc_stream_mtx;
163 };
164
165 int hdaudio_attach(device_t, struct hdaudio_softc *);
166 int hdaudio_detach(struct hdaudio_softc *, int);
167 bool hdaudio_resume(struct hdaudio_softc *);
168 int hdaudio_rescan(struct hdaudio_softc *, const char *, const int *);
169 void hdaudio_childdet(struct hdaudio_softc *, device_t);
170
171 uint32_t hdaudio_command(struct hdaudio_codec *, int, uint32_t, uint32_t);
172 uint32_t hdaudio_command_unlocked(struct hdaudio_codec *, int, uint32_t,
173 uint32_t);
174 int hdaudio_intr(struct hdaudio_softc *);
175
176 int hdaudio_dma_alloc(struct hdaudio_softc *, struct hdaudio_dma *, int);
177 void hdaudio_dma_free(struct hdaudio_softc *, struct hdaudio_dma *);
178
179 struct hdaudio_stream * hdaudio_stream_establish(struct hdaudio_softc *,
180 enum hdaudio_stream_type,
181 int (*)(struct hdaudio_stream *), void *);
182 void hdaudio_stream_disestablish(struct hdaudio_stream *);
183 void hdaudio_stream_start(struct hdaudio_stream *, int, bus_size_t,
184 const audio_params_t *);
185 void hdaudio_stream_stop(struct hdaudio_stream *);
186 void hdaudio_stream_reset(struct hdaudio_stream *);
187 int hdaudio_stream_tag(struct hdaudio_stream *);
188 uint16_t hdaudio_stream_param(struct hdaudio_stream *, const audio_params_t *);
189
190 static __inline uint8_t
_hda_read1(struct hdaudio_softc * sc,bus_size_t off)191 _hda_read1(struct hdaudio_softc *sc, bus_size_t off)
192 {
193 if (ISSET(sc->sc_flags, HDAUDIO_FLAG_32BIT)) {
194 return bus_space_read_4(sc->sc_memt, sc->sc_memh, off & -4) >>
195 (8 * (off & 3));
196 } else {
197 return bus_space_read_1(sc->sc_memt, sc->sc_memh, off);
198 }
199 }
200
201 static __inline uint16_t
_hda_read2(struct hdaudio_softc * sc,bus_size_t off)202 _hda_read2(struct hdaudio_softc *sc, bus_size_t off)
203 {
204 if (ISSET(sc->sc_flags, HDAUDIO_FLAG_32BIT)) {
205 return bus_space_read_4(sc->sc_memt, sc->sc_memh, off & -4) >>
206 (8 * (off & 2));
207 } else {
208 return bus_space_read_2(sc->sc_memt, sc->sc_memh, off);
209 }
210 }
211
212 #define hda_read1 _hda_read1
213 #define hda_read2 _hda_read2
214 #define hda_read4(sc, off) \
215 bus_space_read_4((sc)->sc_memt, (sc)->sc_memh, (off))
216
217 static __inline void
_hda_write1(struct hdaudio_softc * sc,bus_size_t off,uint8_t val)218 _hda_write1(struct hdaudio_softc *sc, bus_size_t off, uint8_t val)
219 {
220 if (ISSET(sc->sc_flags, HDAUDIO_FLAG_32BIT)) {
221 const size_t shift = 8 * (off & 3);
222 off &= -4;
223 uint32_t tmp = bus_space_read_4(sc->sc_memt, sc->sc_memh, off);
224 tmp = (val << shift) | (tmp & ~(0xff << shift));
225 bus_space_write_4(sc->sc_memt, sc->sc_memh, off, tmp);
226 } else {
227 bus_space_write_1(sc->sc_memt, sc->sc_memh, off, val);
228 }
229 }
230
231 static __inline void
_hda_write2(struct hdaudio_softc * sc,bus_size_t off,uint16_t val)232 _hda_write2(struct hdaudio_softc *sc, bus_size_t off, uint16_t val)
233 {
234 if (ISSET(sc->sc_flags, HDAUDIO_FLAG_32BIT)) {
235 const size_t shift = 8 * (off & 2);
236 off &= -4;
237 uint32_t tmp = bus_space_read_4(sc->sc_memt, sc->sc_memh, off);
238 tmp = (val << shift) | (tmp & ~(0xffff << shift));
239 bus_space_write_4(sc->sc_memt, sc->sc_memh, off, tmp);
240 } else {
241 bus_space_write_2(sc->sc_memt, sc->sc_memh, off, val);
242 }
243 }
244
245 #define hda_write1 _hda_write1
246 #define hda_write2 _hda_write2
247 #define hda_write4(sc, off, val) \
248 bus_space_write_4((sc)->sc_memt, (sc)->sc_memh, (off), (val))
249
250 #endif /* !_HDAUDIOVAR_H */
251