1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * HD-audio core bus driver 4 */ 5 6 #include <linux/init.h> 7 #include <linux/io.h> 8 #include <linux/device.h> 9 #include <linux/module.h> 10 #include <linux/export.h> 11 #include <sound/hdaudio.h> 12 #include "local.h" 13 #include "trace.h" 14 15 static void snd_hdac_bus_process_unsol_events(struct work_struct *work); 16 17 static const struct hdac_bus_ops default_ops = { 18 .command = snd_hdac_bus_send_cmd, 19 .get_response = snd_hdac_bus_get_response, 20 .link_power = snd_hdac_bus_link_power, 21 }; 22 23 /** 24 * snd_hdac_bus_init - initialize a HD-audio bas bus 25 * @bus: the pointer to bus object 26 * @dev: device pointer 27 * @ops: bus verb operators 28 * 29 * Returns 0 if successful, or a negative error code. 30 */ 31 int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev, 32 const struct hdac_bus_ops *ops) 33 { 34 memset(bus, 0, sizeof(*bus)); 35 bus->dev = dev; 36 if (ops) 37 bus->ops = ops; 38 else 39 bus->ops = &default_ops; 40 bus->dma_type = SNDRV_DMA_TYPE_DEV; 41 INIT_LIST_HEAD(&bus->stream_list); 42 INIT_LIST_HEAD(&bus->codec_list); 43 INIT_WORK(&bus->unsol_work, snd_hdac_bus_process_unsol_events); 44 spin_lock_init(&bus->reg_lock); 45 mutex_init(&bus->cmd_mutex); 46 mutex_init(&bus->lock); 47 INIT_LIST_HEAD(&bus->hlink_list); 48 init_waitqueue_head(&bus->rirb_wq); 49 bus->irq = -1; 50 bus->addr_offset = 0; 51 52 /* 53 * Default value of '8' is as per the HD audio specification (Rev 1.0a). 54 * Following relation is used to derive STRIPE control value. 55 * For sample rate <= 48K: 56 * { ((num_channels * bits_per_sample) / number of SDOs) >= 8 } 57 * For sample rate > 48K: 58 * { ((num_channels * bits_per_sample * rate/48000) / 59 * number of SDOs) >= 8 } 60 */ 61 bus->sdo_limit = 8; 62 63 return 0; 64 } 65 EXPORT_SYMBOL_GPL(snd_hdac_bus_init); 66 67 /** 68 * snd_hdac_bus_exit - clean up a HD-audio bas bus 69 * @bus: the pointer to bus object 70 */ 71 void snd_hdac_bus_exit(struct hdac_bus *bus) 72 { 73 WARN_ON(!list_empty(&bus->stream_list)); 74 WARN_ON(!list_empty(&bus->codec_list)); 75 cancel_work_sync(&bus->unsol_work); 76 } 77 EXPORT_SYMBOL_GPL(snd_hdac_bus_exit); 78 79 /** 80 * snd_hdac_bus_exec_verb - execute a HD-audio verb on the given bus 81 * @bus: bus object 82 * @addr: the HDAC device address 83 * @cmd: HD-audio encoded verb 84 * @res: pointer to store the response, NULL if performing asynchronously 85 * 86 * Returns 0 if successful, or a negative error code. 87 */ 88 int snd_hdac_bus_exec_verb(struct hdac_bus *bus, unsigned int addr, 89 unsigned int cmd, unsigned int *res) 90 { 91 guard(mutex)(&bus->cmd_mutex); 92 return snd_hdac_bus_exec_verb_unlocked(bus, addr, cmd, res); 93 } 94 95 /** 96 * snd_hdac_bus_exec_verb_unlocked - unlocked version 97 * @bus: bus object 98 * @addr: the HDAC device address 99 * @cmd: HD-audio encoded verb 100 * @res: pointer to store the response, NULL if performing asynchronously 101 * 102 * Returns 0 if successful, or a negative error code. 103 */ 104 int snd_hdac_bus_exec_verb_unlocked(struct hdac_bus *bus, unsigned int addr, 105 unsigned int cmd, unsigned int *res) 106 { 107 unsigned int tmp; 108 int err; 109 110 if (cmd == ~0) 111 return -EINVAL; 112 113 if (res) 114 *res = -1; 115 else if (bus->sync_write) 116 res = &tmp; 117 for (;;) { 118 trace_hda_send_cmd(bus, cmd); 119 err = bus->ops->command(bus, cmd); 120 if (err != -EAGAIN) 121 break; 122 /* process pending verbs */ 123 err = bus->ops->get_response(bus, addr, &tmp); 124 if (err) 125 break; 126 } 127 if (!err && res) { 128 err = bus->ops->get_response(bus, addr, res); 129 trace_hda_get_response(bus, addr, *res); 130 } 131 return err; 132 } 133 EXPORT_SYMBOL_GPL(snd_hdac_bus_exec_verb_unlocked); 134 135 /** 136 * snd_hdac_bus_queue_event - add an unsolicited event to queue 137 * @bus: the BUS 138 * @res: unsolicited event (lower 32bit of RIRB entry) 139 * @res_ex: codec addr and flags (upper 32bit or RIRB entry) 140 * 141 * Adds the given event to the queue. The events are processed in 142 * the workqueue asynchronously. Call this function in the interrupt 143 * hanlder when RIRB receives an unsolicited event. 144 */ 145 void snd_hdac_bus_queue_event(struct hdac_bus *bus, u32 res, u32 res_ex) 146 { 147 unsigned int wp; 148 149 if (!bus) 150 return; 151 152 trace_hda_unsol_event(bus, res, res_ex); 153 wp = (bus->unsol_wp + 1) % HDA_UNSOL_QUEUE_SIZE; 154 bus->unsol_wp = wp; 155 156 wp <<= 1; 157 bus->unsol_queue[wp] = res; 158 bus->unsol_queue[wp + 1] = res_ex; 159 160 schedule_work(&bus->unsol_work); 161 } 162 163 /* 164 * process queued unsolicited events 165 */ 166 static void snd_hdac_bus_process_unsol_events(struct work_struct *work) 167 { 168 struct hdac_bus *bus = container_of(work, struct hdac_bus, unsol_work); 169 struct hdac_device *codec; 170 struct hdac_driver *drv; 171 unsigned int rp, caddr, res; 172 173 spin_lock_irq(&bus->reg_lock); 174 while (bus->unsol_rp != bus->unsol_wp) { 175 rp = (bus->unsol_rp + 1) % HDA_UNSOL_QUEUE_SIZE; 176 bus->unsol_rp = rp; 177 rp <<= 1; 178 res = bus->unsol_queue[rp]; 179 caddr = bus->unsol_queue[rp + 1]; 180 if (!(caddr & (1 << 4))) /* no unsolicited event? */ 181 continue; 182 codec = bus->caddr_tbl[caddr & 0x0f]; 183 if (!codec || !codec->registered) 184 continue; 185 spin_unlock_irq(&bus->reg_lock); 186 drv = drv_to_hdac_driver(codec->dev.driver); 187 if (drv->unsol_event) 188 drv->unsol_event(codec, res); 189 spin_lock_irq(&bus->reg_lock); 190 } 191 spin_unlock_irq(&bus->reg_lock); 192 } 193 194 /** 195 * snd_hdac_bus_add_device - Add a codec to bus 196 * @bus: HDA core bus 197 * @codec: HDA core device to add 198 * 199 * Adds the given codec to the list in the bus. The caddr_tbl array 200 * and codec_powered bits are updated, as well. 201 * Returns zero if success, or a negative error code. 202 */ 203 int snd_hdac_bus_add_device(struct hdac_bus *bus, struct hdac_device *codec) 204 { 205 if (bus->caddr_tbl[codec->addr]) { 206 dev_err(bus->dev, "address 0x%x is already occupied\n", 207 codec->addr); 208 return -EBUSY; 209 } 210 211 list_add_tail(&codec->list, &bus->codec_list); 212 bus->caddr_tbl[codec->addr] = codec; 213 set_bit(codec->addr, &bus->codec_powered); 214 bus->num_codecs++; 215 return 0; 216 } 217 218 /** 219 * snd_hdac_bus_remove_device - Remove a codec from bus 220 * @bus: HDA core bus 221 * @codec: HDA core device to remove 222 */ 223 void snd_hdac_bus_remove_device(struct hdac_bus *bus, 224 struct hdac_device *codec) 225 { 226 WARN_ON(bus != codec->bus); 227 if (list_empty(&codec->list)) 228 return; 229 list_del_init(&codec->list); 230 bus->caddr_tbl[codec->addr] = NULL; 231 clear_bit(codec->addr, &bus->codec_powered); 232 bus->num_codecs--; 233 flush_work(&bus->unsol_work); 234 } 235 236 #ifdef CONFIG_SND_HDA_ALIGNED_MMIO 237 /* Helpers for aligned read/write of mmio space, for Tegra */ 238 unsigned int snd_hdac_aligned_read(void __iomem *addr, unsigned int mask) 239 { 240 void __iomem *aligned_addr = 241 (void __iomem *)((unsigned long)(addr) & ~0x3); 242 unsigned int shift = ((unsigned long)(addr) & 0x3) << 3; 243 unsigned int v; 244 245 v = readl(aligned_addr); 246 return (v >> shift) & mask; 247 } 248 EXPORT_SYMBOL_GPL(snd_hdac_aligned_read); 249 250 void snd_hdac_aligned_write(unsigned int val, void __iomem *addr, 251 unsigned int mask) 252 { 253 void __iomem *aligned_addr = 254 (void __iomem *)((unsigned long)(addr) & ~0x3); 255 unsigned int shift = ((unsigned long)(addr) & 0x3) << 3; 256 unsigned int v; 257 258 v = readl(aligned_addr); 259 v &= ~(mask << shift); 260 v |= val << shift; 261 writel(v, aligned_addr); 262 } 263 EXPORT_SYMBOL_GPL(snd_hdac_aligned_write); 264 #endif /* CONFIG_SND_HDA_ALIGNED_MMIO */ 265 266 void snd_hdac_codec_link_up(struct hdac_device *codec) 267 { 268 struct hdac_bus *bus = codec->bus; 269 270 if (bus->ops->link_power) 271 bus->ops->link_power(codec, true); 272 else 273 snd_hdac_bus_link_power(codec, true); 274 } 275 EXPORT_SYMBOL_GPL(snd_hdac_codec_link_up); 276 277 void snd_hdac_codec_link_down(struct hdac_device *codec) 278 { 279 struct hdac_bus *bus = codec->bus; 280 281 if (bus->ops->link_power) 282 bus->ops->link_power(codec, false); 283 else 284 snd_hdac_bus_link_power(codec, false); 285 } 286 EXPORT_SYMBOL_GPL(snd_hdac_codec_link_down); 287