| 1 | |
| 2 | |
| 3 | * HD-audio controller helpers
|
| 4 |
|
| 5 |
|
| 6 | #include <linux/kernel.h>
|
| 7 | #include <linux/delay.h>
|
| 8 | #include <linux/export.h>
|
| 9 | #include <sound/core.h>
|
| 10 | #include <sound/hdaudio.h>
|
| 11 | #include <sound/hda_register.h>
|
| 12 | #include "local.h"
|
| 13 |
|
| 14 |
|
| 15 | static void azx_clear_corbrp(struct hdac_bus *bus)
|
| 16 | {
|
| 17 | int timeout;
|
| 18 |
|
| 19 | for (timeout = 1000; timeout > 0; timeout--) {
|
| 20 | if (snd_hdac_chip_readw(bus, CORBRP) & AZX_CORBRP_RST)
|
| 21 | break;
|
| 22 | udelay(1);
|
| 23 | }
|
| 24 | if (timeout <= 0)
|
| 25 | dev_err(bus->dev, "CORB reset timeout#1, CORBRP = %d\n",
|
| 26 | snd_hdac_chip_readw(bus, CORBRP));
|
| 27 |
|
| 28 | snd_hdac_chip_writew(bus, CORBRP, 0);
|
| 29 | for (timeout = 1000; timeout > 0; timeout--) {
|
| 30 | if (snd_hdac_chip_readw(bus, CORBRP) == 0)
|
| 31 | break;
|
| 32 | udelay(1);
|
| 33 | }
|
| 34 | if (timeout <= 0)
|
| 35 | dev_err(bus->dev, "CORB reset timeout#2, CORBRP = %d\n",
|
| 36 | snd_hdac_chip_readw(bus, CORBRP));
|
| 37 | }
|
| 38 |
|
| 39 | |
| 40 | * snd_hdac_bus_init_cmd_io - set up CORB/RIRB buffers
|
| 41 | * @bus: HD-audio core bus
|
| 42 |
|
| 43 | void snd_hdac_bus_init_cmd_io(struct hdac_bus *bus)
|
| 44 | {
|
| 45 | WARN_ON_ONCE(!bus->rb.area);
|
| 46 |
|
| 47 | guard(spinlock_irq)(&bus->reg_lock);
|
| 48 |
|
| 49 | bus->corb.addr = bus->rb.addr;
|
| 50 | bus->corb.buf = (__le32 *)bus->rb.area;
|
| 51 | snd_hdac_chip_writel(bus, CORBLBASE, (u32)(bus->corb.addr + bus->addr_offset));
|
| 52 | snd_hdac_chip_writel(bus, CORBUBASE, upper_32_bits(bus->corb.addr + bus->addr_offset));
|
| 53 |
|
| 54 |
|
| 55 | snd_hdac_chip_writeb(bus, CORBSIZE, 0x02);
|
| 56 |
|
| 57 | snd_hdac_chip_writew(bus, CORBWP, 0);
|
| 58 |
|
| 59 |
|
| 60 | snd_hdac_chip_writew(bus, CORBRP, AZX_CORBRP_RST);
|
| 61 | if (!bus->corbrp_self_clear)
|
| 62 | azx_clear_corbrp(bus);
|
| 63 |
|
| 64 |
|
| 65 | if (!bus->use_pio_for_commands)
|
| 66 | snd_hdac_chip_writeb(bus, CORBCTL, AZX_CORBCTL_RUN);
|
| 67 |
|
| 68 |
|
| 69 | bus->rirb.addr = bus->rb.addr + 2048;
|
| 70 | bus->rirb.buf = (__le32 *)(bus->rb.area + 2048);
|
| 71 | bus->rirb.wp = bus->rirb.rp = 0;
|
| 72 | memset(bus->rirb.cmds, 0, sizeof(bus->rirb.cmds));
|
| 73 | snd_hdac_chip_writel(bus, RIRBLBASE, (u32)(bus->rirb.addr + bus->addr_offset));
|
| 74 | snd_hdac_chip_writel(bus, RIRBUBASE, upper_32_bits(bus->rirb.addr + bus->addr_offset));
|
| 75 |
|
| 76 |
|
| 77 | snd_hdac_chip_writeb(bus, RIRBSIZE, 0x02);
|
| 78 |
|
| 79 | snd_hdac_chip_writew(bus, RIRBWP, AZX_RIRBWP_RST);
|
| 80 |
|
| 81 | snd_hdac_chip_writew(bus, RINTCNT, 1);
|
| 82 |
|
| 83 | if (bus->not_use_interrupts)
|
| 84 | snd_hdac_chip_writeb(bus, RIRBCTL, AZX_RBCTL_DMA_EN);
|
| 85 | else
|
| 86 | snd_hdac_chip_writeb(bus, RIRBCTL, AZX_RBCTL_DMA_EN | AZX_RBCTL_IRQ_EN);
|
| 87 |
|
| 88 | snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL);
|
| 89 | }
|
| 90 | EXPORT_SYMBOL_GPL(snd_hdac_bus_init_cmd_io);
|
| 91 |
|
| 92 |
|
| 93 | static void hdac_wait_for_cmd_dmas(struct hdac_bus *bus)
|
| 94 | {
|
| 95 | unsigned long timeout;
|
| 96 |
|
| 97 | timeout = jiffies + msecs_to_jiffies(100);
|
| 98 | while ((snd_hdac_chip_readb(bus, RIRBCTL) & AZX_RBCTL_DMA_EN)
|
| 99 | && time_before(jiffies, timeout))
|
| 100 | udelay(10);
|
| 101 |
|
| 102 | timeout = jiffies + msecs_to_jiffies(100);
|
| 103 | while ((snd_hdac_chip_readb(bus, CORBCTL) & AZX_CORBCTL_RUN)
|
| 104 | && time_before(jiffies, timeout))
|
| 105 | udelay(10);
|
| 106 | }
|
| 107 |
|
| 108 | |
| 109 | * snd_hdac_bus_stop_cmd_io - clean up CORB/RIRB buffers
|
| 110 | * @bus: HD-audio core bus
|
| 111 |
|
| 112 | void snd_hdac_bus_stop_cmd_io(struct hdac_bus *bus)
|
| 113 | {
|
| 114 | scoped_guard(spinlock_irq, &bus->reg_lock) {
|
| 115 |
|
| 116 | snd_hdac_chip_writeb(bus, RIRBCTL, 0);
|
| 117 | snd_hdac_chip_writeb(bus, CORBCTL, 0);
|
| 118 | }
|
| 119 |
|
| 120 | hdac_wait_for_cmd_dmas(bus);
|
| 121 |
|
| 122 | guard(spinlock_irq)(&bus->reg_lock);
|
| 123 |
|
| 124 | snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, 0);
|
| 125 | }
|
| 126 | EXPORT_SYMBOL_GPL(snd_hdac_bus_stop_cmd_io);
|
| 127 |
|
| 128 | static unsigned int azx_command_addr(u32 cmd)
|
| 129 | {
|
| 130 | unsigned int addr = cmd >> 28;
|
| 131 |
|
| 132 | if (snd_BUG_ON(addr >= HDA_MAX_CODECS))
|
| 133 | addr = 0;
|
| 134 | return addr;
|
| 135 | }
|
| 136 |
|
| 137 |
|
| 138 | static int snd_hdac_bus_wait_for_pio_response(struct hdac_bus *bus,
|
| 139 | unsigned int addr)
|
| 140 | {
|
| 141 | int timeout = 50;
|
| 142 |
|
| 143 | while (timeout--) {
|
| 144 |
|
| 145 | if (snd_hdac_chip_readw(bus, IRS) & AZX_IRS_VALID) {
|
| 146 |
|
| 147 | bus->rirb.res[addr] = snd_hdac_chip_readl(bus, IR);
|
| 148 | return 0;
|
| 149 | }
|
| 150 | udelay(1);
|
| 151 | }
|
| 152 |
|
| 153 | dev_dbg_ratelimited(bus->dev, "get_response_pio timeout: IRS=%#x\n",
|
| 154 | snd_hdac_chip_readw(bus, IRS));
|
| 155 |
|
| 156 | bus->rirb.res[addr] = -1;
|
| 157 |
|
| 158 | return -EIO;
|
| 159 | }
|
| 160 |
|
| 161 | |
| 162 | * snd_hdac_bus_send_cmd_pio - send a command verb via Immediate Command
|
| 163 | * @bus: HD-audio core bus
|
| 164 | * @val: encoded verb value to send
|
| 165 | *
|
| 166 | * Returns zero for success or a negative error code.
|
| 167 |
|
| 168 | static int snd_hdac_bus_send_cmd_pio(struct hdac_bus *bus, unsigned int val)
|
| 169 | {
|
| 170 | unsigned int addr = azx_command_addr(val);
|
| 171 | int timeout = 50;
|
| 172 |
|
| 173 | guard(spinlock_irq)(&bus->reg_lock);
|
| 174 |
|
| 175 | while (timeout--) {
|
| 176 |
|
| 177 | if (!((snd_hdac_chip_readw(bus, IRS) & AZX_IRS_BUSY))) {
|
| 178 |
|
| 179 | snd_hdac_chip_updatew(bus, IRS, AZX_IRS_VALID, AZX_IRS_VALID);
|
| 180 | snd_hdac_chip_writel(bus, IC, val);
|
| 181 |
|
| 182 | snd_hdac_chip_updatew(bus, IRS, AZX_IRS_BUSY, AZX_IRS_BUSY);
|
| 183 |
|
| 184 | return snd_hdac_bus_wait_for_pio_response(bus, addr);
|
| 185 | }
|
| 186 | udelay(1);
|
| 187 | }
|
| 188 |
|
| 189 | dev_dbg_ratelimited(bus->dev, "send_cmd_pio timeout: IRS=%#x, val=%#x\n",
|
| 190 | snd_hdac_chip_readw(bus, IRS), val);
|
| 191 |
|
| 192 | return -EIO;
|
| 193 | }
|
| 194 |
|
| 195 | |
| 196 | * snd_hdac_bus_get_response_pio - receive a response via Immediate Response
|
| 197 | * @bus: HD-audio core bus
|
| 198 | * @addr: codec address
|
| 199 | * @res: pointer to store the value, NULL when not needed
|
| 200 | *
|
| 201 | * Returns zero if a value is read, or a negative error code.
|
| 202 |
|
| 203 | static int snd_hdac_bus_get_response_pio(struct hdac_bus *bus,
|
| 204 | unsigned int addr, unsigned int *res)
|
| 205 | {
|
| 206 | if (res)
|
| 207 | *res = bus->rirb.res[addr];
|
| 208 |
|
| 209 | return 0;
|
| 210 | }
|
| 211 |
|
| 212 | |
| 213 | * snd_hdac_bus_send_cmd_corb - send a command verb via CORB
|
| 214 | * @bus: HD-audio core bus
|
| 215 | * @val: encoded verb value to send
|
| 216 | *
|
| 217 | * Returns zero for success or a negative error code.
|
| 218 |
|
| 219 | static int snd_hdac_bus_send_cmd_corb(struct hdac_bus *bus, unsigned int val)
|
| 220 | {
|
| 221 | unsigned int addr = azx_command_addr(val);
|
| 222 | unsigned int wp, rp;
|
| 223 |
|
| 224 | guard(spinlock_irq)(&bus->reg_lock);
|
| 225 |
|
| 226 | bus->last_cmd[azx_command_addr(val)] = val;
|
| 227 |
|
| 228 |
|
| 229 | wp = snd_hdac_chip_readw(bus, CORBWP);
|
| 230 | if (wp == 0xffff) {
|
| 231 |
|
| 232 | return -EIO;
|
| 233 | }
|
| 234 | wp++;
|
| 235 | wp %= AZX_MAX_CORB_ENTRIES;
|
| 236 |
|
| 237 | rp = snd_hdac_chip_readw(bus, CORBRP);
|
| 238 | if (wp == rp) {
|
| 239 |
|
| 240 | return -EAGAIN;
|
| 241 | }
|
| 242 |
|
| 243 | bus->rirb.cmds[addr]++;
|
| 244 | bus->corb.buf[wp] = cpu_to_le32(val);
|
| 245 | snd_hdac_chip_writew(bus, CORBWP, wp);
|
| 246 |
|
| 247 | return 0;
|
| 248 | }
|
| 249 |
|
| 250 | #define AZX_RIRB_EX_UNSOL_EV (1<<4)
|
| 251 |
|
| 252 | |
| 253 | * snd_hdac_bus_update_rirb - retrieve RIRB entries
|
| 254 | * @bus: HD-audio core bus
|
| 255 | *
|
| 256 | * Usually called from interrupt handler.
|
| 257 | * The caller needs bus->reg_lock spinlock before calling this.
|
| 258 |
|
| 259 | void snd_hdac_bus_update_rirb(struct hdac_bus *bus)
|
| 260 | {
|
| 261 | unsigned int rp, wp;
|
| 262 | unsigned int addr;
|
| 263 | u32 res, res_ex;
|
| 264 |
|
| 265 | wp = snd_hdac_chip_readw(bus, RIRBWP);
|
| 266 | if (wp == 0xffff) {
|
| 267 |
|
| 268 | return;
|
| 269 | }
|
| 270 |
|
| 271 | if (wp == bus->rirb.wp)
|
| 272 | return;
|
| 273 | bus->rirb.wp = wp;
|
| 274 |
|
| 275 | while (bus->rirb.rp != wp) {
|
| 276 | bus->rirb.rp++;
|
| 277 | bus->rirb.rp %= AZX_MAX_RIRB_ENTRIES;
|
| 278 |
|
| 279 | rp = bus->rirb.rp << 1;
|
| 280 | res_ex = le32_to_cpu(bus->rirb.buf[rp + 1]);
|
| 281 | res = le32_to_cpu(bus->rirb.buf[rp]);
|
| 282 | addr = res_ex & 0xf;
|
| 283 | if (addr >= HDA_MAX_CODECS) {
|
| 284 | dev_err(bus->dev,
|
| 285 | "spurious response %#x:%#x, rp = %d, wp = %d",
|
| 286 | res, res_ex, bus->rirb.rp, wp);
|
| 287 | snd_BUG();
|
| 288 | } else if (res_ex & AZX_RIRB_EX_UNSOL_EV)
|
| 289 | snd_hdac_bus_queue_event(bus, res, res_ex);
|
| 290 | else if (bus->rirb.cmds[addr]) {
|
| 291 | bus->rirb.res[addr] = res;
|
| 292 | bus->rirb.cmds[addr]--;
|
| 293 | if (!bus->rirb.cmds[addr] &&
|
| 294 | waitqueue_active(&bus->rirb_wq))
|
| 295 | wake_up(&bus->rirb_wq);
|
| 296 | } else {
|
| 297 | dev_err_ratelimited(bus->dev,
|
| 298 | "spurious response %#x:%#x, last cmd=%#08x\n",
|
| 299 | res, res_ex, bus->last_cmd[addr]);
|
| 300 | }
|
| 301 | }
|
| 302 | }
|
| 303 | EXPORT_SYMBOL_GPL(snd_hdac_bus_update_rirb);
|
| 304 |
|
| 305 | |
| 306 | * snd_hdac_bus_get_response_rirb - receive a response via RIRB
|
| 307 | * @bus: HD-audio core bus
|
| 308 | * @addr: codec address
|
| 309 | * @res: pointer to store the value, NULL when not needed
|
| 310 | *
|
| 311 | * Returns zero if a value is read, or a negative error code.
|
| 312 |
|
| 313 | static int snd_hdac_bus_get_response_rirb(struct hdac_bus *bus,
|
| 314 | unsigned int addr, unsigned int *res)
|
| 315 | {
|
| 316 | unsigned long timeout;
|
| 317 | unsigned long loopcounter;
|
| 318 | wait_queue_entry_t wait;
|
| 319 | bool warned = false;
|
| 320 |
|
| 321 | init_wait_entry(&wait, 0);
|
| 322 | timeout = jiffies + msecs_to_jiffies(1000);
|
| 323 |
|
| 324 | for (loopcounter = 0;; loopcounter++) {
|
| 325 | scoped_guard(spinlock_irq, &bus->reg_lock) {
|
| 326 | if (!bus->polling_mode)
|
| 327 | prepare_to_wait(&bus->rirb_wq, &wait,
|
| 328 | TASK_UNINTERRUPTIBLE);
|
| 329 | if (bus->polling_mode)
|
| 330 | snd_hdac_bus_update_rirb(bus);
|
| 331 | if (!bus->rirb.cmds[addr]) {
|
| 332 | if (res)
|
| 333 | *res = bus->rirb.res[addr];
|
| 334 | if (!bus->polling_mode)
|
| 335 | finish_wait(&bus->rirb_wq, &wait);
|
| 336 | return 0;
|
| 337 | }
|
| 338 | }
|
| 339 | if (time_after(jiffies, timeout))
|
| 340 | break;
|
| 341 | #define LOOP_COUNT_MAX 3000
|
| 342 | if (!bus->polling_mode) {
|
| 343 | schedule_timeout(msecs_to_jiffies(2));
|
| 344 | } else if (bus->needs_damn_long_delay ||
|
| 345 | loopcounter > LOOP_COUNT_MAX) {
|
| 346 | if (loopcounter > LOOP_COUNT_MAX && !warned) {
|
| 347 | dev_dbg_ratelimited(bus->dev,
|
| 348 | "too slow response, last cmd=%#08x\n",
|
| 349 | bus->last_cmd[addr]);
|
| 350 | warned = true;
|
| 351 | }
|
| 352 | msleep(2);
|
| 353 | } else {
|
| 354 | udelay(10);
|
| 355 | cond_resched();
|
| 356 | }
|
| 357 | }
|
| 358 |
|
| 359 | if (!bus->polling_mode)
|
| 360 | finish_wait(&bus->rirb_wq, &wait);
|
| 361 |
|
| 362 | return -EIO;
|
| 363 | }
|
| 364 |
|
| 365 | |
| 366 | * snd_hdac_bus_send_cmd - send a command verb via CORB or PIO
|
| 367 | * @bus: HD-audio core bus
|
| 368 | * @val: encoded verb value to send
|
| 369 | *
|
| 370 | * Returns zero for success or a negative error code.
|
| 371 |
|
| 372 | int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val)
|
| 373 | {
|
| 374 | if (bus->use_pio_for_commands)
|
| 375 | return snd_hdac_bus_send_cmd_pio(bus, val);
|
| 376 |
|
| 377 | return snd_hdac_bus_send_cmd_corb(bus, val);
|
| 378 | }
|
| 379 | EXPORT_SYMBOL_GPL(snd_hdac_bus_send_cmd);
|
| 380 |
|
| 381 | |
| 382 | * snd_hdac_bus_get_response - receive a response via RIRB or PIO
|
| 383 | * @bus: HD-audio core bus
|
| 384 | * @addr: codec address
|
| 385 | * @res: pointer to store the value, NULL when not needed
|
| 386 | *
|
| 387 | * Returns zero if a value is read, or a negative error code.
|
| 388 |
|
| 389 | int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr,
|
| 390 | unsigned int *res)
|
| 391 | {
|
| 392 | if (bus->use_pio_for_commands)
|
| 393 | return snd_hdac_bus_get_response_pio(bus, addr, res);
|
| 394 |
|
| 395 | return snd_hdac_bus_get_response_rirb(bus, addr, res);
|
| 396 | }
|
| 397 | EXPORT_SYMBOL_GPL(snd_hdac_bus_get_response);
|
| 398 |
|
| 399 | #define HDAC_MAX_CAPS 10
|
| 400 | |
| 401 | * snd_hdac_bus_parse_capabilities - parse capability structure
|
| 402 | * @bus: the pointer to bus object
|
| 403 | *
|
| 404 | * Returns 0 if successful, or a negative error code.
|
| 405 |
|
| 406 | int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus)
|
| 407 | {
|
| 408 | unsigned int cur_cap;
|
| 409 | unsigned int offset;
|
| 410 | unsigned int counter = 0;
|
| 411 |
|
| 412 | offset = snd_hdac_chip_readw(bus, LLCH);
|
| 413 |
|
| 414 |
|
| 415 | do {
|
| 416 | cur_cap = _snd_hdac_chip_readl(bus, offset);
|
| 417 |
|
| 418 | dev_dbg(bus->dev, "Capability version: 0x%x\n",
|
| 419 | (cur_cap & AZX_CAP_HDR_VER_MASK) >> AZX_CAP_HDR_VER_OFF);
|
| 420 |
|
| 421 | dev_dbg(bus->dev, "HDA capability ID: 0x%x\n",
|
| 422 | (cur_cap & AZX_CAP_HDR_ID_MASK) >> AZX_CAP_HDR_ID_OFF);
|
| 423 |
|
| 424 | if (cur_cap == -1) {
|
| 425 | dev_dbg(bus->dev, "Invalid capability reg read\n");
|
| 426 | break;
|
| 427 | }
|
| 428 |
|
| 429 | switch ((cur_cap & AZX_CAP_HDR_ID_MASK) >> AZX_CAP_HDR_ID_OFF) {
|
| 430 | case AZX_ML_CAP_ID:
|
| 431 | dev_dbg(bus->dev, "Found ML capability\n");
|
| 432 | bus->mlcap = bus->remap_addr + offset;
|
| 433 | break;
|
| 434 |
|
| 435 | case AZX_GTS_CAP_ID:
|
| 436 | dev_dbg(bus->dev, "Found GTS capability offset=%x\n", offset);
|
| 437 | bus->gtscap = bus->remap_addr + offset;
|
| 438 | break;
|
| 439 |
|
| 440 | case AZX_PP_CAP_ID:
|
| 441 |
|
| 442 | dev_dbg(bus->dev, "Found PP capability offset=%x\n", offset);
|
| 443 | bus->ppcap = bus->remap_addr + offset;
|
| 444 | break;
|
| 445 |
|
| 446 | case AZX_SPB_CAP_ID:
|
| 447 |
|
| 448 | dev_dbg(bus->dev, "Found SPB capability\n");
|
| 449 | bus->spbcap = bus->remap_addr + offset;
|
| 450 | break;
|
| 451 |
|
| 452 | case AZX_DRSM_CAP_ID:
|
| 453 |
|
| 454 | dev_dbg(bus->dev, "Found DRSM capability\n");
|
| 455 | bus->drsmcap = bus->remap_addr + offset;
|
| 456 | break;
|
| 457 |
|
| 458 | default:
|
| 459 | dev_err(bus->dev, "Unknown capability %d\n", cur_cap);
|
| 460 | cur_cap = 0;
|
| 461 | break;
|
| 462 | }
|
| 463 |
|
| 464 | counter++;
|
| 465 |
|
| 466 | if (counter > HDAC_MAX_CAPS) {
|
| 467 | dev_err(bus->dev, "We exceeded HDAC capabilities!!!\n");
|
| 468 | break;
|
| 469 | }
|
| 470 |
|
| 471 |
|
| 472 | offset = cur_cap & AZX_CAP_HDR_NXT_PTR_MASK;
|
| 473 |
|
| 474 | } while (offset);
|
| 475 |
|
| 476 | return 0;
|
| 477 | }
|
| 478 | EXPORT_SYMBOL_GPL(snd_hdac_bus_parse_capabilities);
|
| 479 |
|
| 480 | |
| 481 | * Lowlevel interface
|
| 482 |
|
| 483 |
|
| 484 | |
| 485 | * snd_hdac_bus_enter_link_reset - enter link reset
|
| 486 | * @bus: HD-audio core bus
|
| 487 | *
|
| 488 | * Enter to the link reset state.
|
| 489 |
|
| 490 | void snd_hdac_bus_enter_link_reset(struct hdac_bus *bus)
|
| 491 | {
|
| 492 | unsigned long timeout;
|
| 493 |
|
| 494 |
|
| 495 | snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_RESET, 0);
|
| 496 |
|
| 497 | timeout = jiffies + msecs_to_jiffies(100);
|
| 498 | while ((snd_hdac_chip_readb(bus, GCTL) & AZX_GCTL_RESET) &&
|
| 499 | time_before(jiffies, timeout))
|
| 500 | usleep_range(500, 1000);
|
| 501 | }
|
| 502 | EXPORT_SYMBOL_GPL(snd_hdac_bus_enter_link_reset);
|
| 503 |
|
| 504 | |
| 505 | * snd_hdac_bus_exit_link_reset - exit link reset
|
| 506 | * @bus: HD-audio core bus
|
| 507 | *
|
| 508 | * Exit from the link reset state.
|
| 509 |
|
| 510 | void snd_hdac_bus_exit_link_reset(struct hdac_bus *bus)
|
| 511 | {
|
| 512 | unsigned long timeout;
|
| 513 |
|
| 514 | if (bus->access_sdnctl_in_dword)
|
| 515 | snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_RESET, AZX_GCTL_RESET);
|
| 516 | else
|
| 517 | snd_hdac_chip_updateb(bus, GCTL, AZX_GCTL_RESET, AZX_GCTL_RESET);
|
| 518 |
|
| 519 | timeout = jiffies + msecs_to_jiffies(100);
|
| 520 | while (!snd_hdac_chip_readb(bus, GCTL) && time_before(jiffies, timeout))
|
| 521 | usleep_range(500, 1000);
|
| 522 | }
|
| 523 | EXPORT_SYMBOL_GPL(snd_hdac_bus_exit_link_reset);
|
| 524 |
|
| 525 |
|
| 526 | int snd_hdac_bus_reset_link(struct hdac_bus *bus, bool full_reset)
|
| 527 | {
|
| 528 | if (!full_reset)
|
| 529 | goto skip_reset;
|
| 530 |
|
| 531 |
|
| 532 | if (snd_hdac_chip_readb(bus, GCTL) & AZX_GCTL_RESET)
|
| 533 | snd_hdac_chip_writew(bus, STATESTS, STATESTS_INT_MASK);
|
| 534 |
|
| 535 |
|
| 536 | snd_hdac_bus_enter_link_reset(bus);
|
| 537 |
|
| 538 | |
| 539 | * Rev 0.9 section 5.5.1
|
| 540 |
|
| 541 | usleep_range(500, 1000);
|
| 542 |
|
| 543 |
|
| 544 | snd_hdac_bus_exit_link_reset(bus);
|
| 545 |
|
| 546 |
|
| 547 | usleep_range(1000, 1200);
|
| 548 |
|
| 549 | skip_reset:
|
| 550 |
|
| 551 | if (!snd_hdac_chip_readb(bus, GCTL)) {
|
| 552 | dev_dbg(bus->dev, "controller not ready!\n");
|
| 553 | return -EBUSY;
|
| 554 | }
|
| 555 |
|
| 556 |
|
| 557 | if (!bus->codec_mask) {
|
| 558 | bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS);
|
| 559 | dev_dbg(bus->dev, "codec_mask = 0x%lx\n", bus->codec_mask);
|
| 560 | }
|
| 561 |
|
| 562 | return 0;
|
| 563 | }
|
| 564 | EXPORT_SYMBOL_GPL(snd_hdac_bus_reset_link);
|
| 565 |
|
| 566 |
|
| 567 | static void azx_int_enable(struct hdac_bus *bus)
|
| 568 | {
|
| 569 |
|
| 570 | snd_hdac_chip_updatel(bus, INTCTL,
|
| 571 | AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN,
|
| 572 | AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN);
|
| 573 | }
|
| 574 |
|
| 575 |
|
| 576 | static void azx_int_disable(struct hdac_bus *bus)
|
| 577 | {
|
| 578 | struct hdac_stream *azx_dev;
|
| 579 |
|
| 580 |
|
| 581 | list_for_each_entry(azx_dev, &bus->stream_list, list)
|
| 582 | if (bus->access_sdnctl_in_dword)
|
| 583 | snd_hdac_stream_updatel(azx_dev, SD_CTL, SD_INT_MASK, 0);
|
| 584 | else
|
| 585 | snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_INT_MASK, 0);
|
| 586 |
|
| 587 |
|
| 588 | snd_hdac_chip_writel(bus, INTCTL, 0);
|
| 589 | }
|
| 590 |
|
| 591 |
|
| 592 | static void azx_int_clear(struct hdac_bus *bus)
|
| 593 | {
|
| 594 | struct hdac_stream *azx_dev;
|
| 595 |
|
| 596 |
|
| 597 | list_for_each_entry(azx_dev, &bus->stream_list, list)
|
| 598 | snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK);
|
| 599 |
|
| 600 |
|
| 601 | snd_hdac_chip_writew(bus, STATESTS, STATESTS_INT_MASK);
|
| 602 |
|
| 603 |
|
| 604 | snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
|
| 605 |
|
| 606 |
|
| 607 | snd_hdac_chip_writel(bus, INTSTS, AZX_INT_CTRL_EN | AZX_INT_ALL_STREAM);
|
| 608 | }
|
| 609 |
|
| 610 | |
| 611 | * snd_hdac_bus_init_chip - reset and start the controller registers
|
| 612 | * @bus: HD-audio core bus
|
| 613 | * @full_reset: Do full reset
|
| 614 |
|
| 615 | bool snd_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset)
|
| 616 | {
|
| 617 | if (bus->chip_init)
|
| 618 | return false;
|
| 619 |
|
| 620 |
|
| 621 | snd_hdac_bus_reset_link(bus, full_reset);
|
| 622 |
|
| 623 |
|
| 624 | azx_int_clear(bus);
|
| 625 |
|
| 626 |
|
| 627 | snd_hdac_bus_init_cmd_io(bus);
|
| 628 |
|
| 629 |
|
| 630 | azx_int_enable(bus);
|
| 631 |
|
| 632 |
|
| 633 | if (bus->use_posbuf && bus->posbuf.addr) {
|
| 634 | snd_hdac_chip_writel(bus, DPLBASE, (u32)(bus->posbuf.addr + bus->addr_offset));
|
| 635 | snd_hdac_chip_writel(bus, DPUBASE, upper_32_bits(bus->posbuf.addr + bus->addr_offset));
|
| 636 | }
|
| 637 |
|
| 638 | bus->chip_init = true;
|
| 639 |
|
| 640 | return true;
|
| 641 | }
|
| 642 | EXPORT_SYMBOL_GPL(snd_hdac_bus_init_chip);
|
| 643 |
|
| 644 | |
| 645 | * snd_hdac_bus_stop_chip - disable the whole IRQ and I/Os
|
| 646 | * @bus: HD-audio core bus
|
| 647 |
|
| 648 | void snd_hdac_bus_stop_chip(struct hdac_bus *bus)
|
| 649 | {
|
| 650 | if (!bus->chip_init)
|
| 651 | return;
|
| 652 |
|
| 653 |
|
| 654 | azx_int_disable(bus);
|
| 655 | azx_int_clear(bus);
|
| 656 |
|
| 657 |
|
| 658 | snd_hdac_bus_stop_cmd_io(bus);
|
| 659 |
|
| 660 |
|
| 661 | if (bus->posbuf.addr) {
|
| 662 | snd_hdac_chip_writel(bus, DPLBASE, 0);
|
| 663 | snd_hdac_chip_writel(bus, DPUBASE, 0);
|
| 664 | }
|
| 665 |
|
| 666 | bus->chip_init = false;
|
| 667 | }
|
| 668 | EXPORT_SYMBOL_GPL(snd_hdac_bus_stop_chip);
|
| 669 |
|
| 670 | |
| 671 | * snd_hdac_bus_handle_stream_irq - interrupt handler for streams
|
| 672 | * @bus: HD-audio core bus
|
| 673 | * @status: INTSTS register value
|
| 674 | * @ack: callback to be called for woken streams
|
| 675 | *
|
| 676 | * Returns the bits of handled streams, or zero if no stream is handled.
|
| 677 |
|
| 678 | int snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status,
|
| 679 | void (*ack)(struct hdac_bus *,
|
| 680 | struct hdac_stream *))
|
| 681 | {
|
| 682 | struct hdac_stream *azx_dev;
|
| 683 | u8 sd_status;
|
| 684 | int handled = 0;
|
| 685 |
|
| 686 | list_for_each_entry(azx_dev, &bus->stream_list, list) {
|
| 687 | if (status & azx_dev->sd_int_sta_mask) {
|
| 688 | sd_status = snd_hdac_stream_readb(azx_dev, SD_STS);
|
| 689 | snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK);
|
| 690 | handled |= 1 << azx_dev->index;
|
| 691 | if (sd_status & (SD_INT_FIFO_ERR | SD_INT_DESC_ERR)) {
|
| 692 | dev_warn_ratelimited(bus->dev,
|
| 693 | "stream %u dma error: 0x%02x\n",
|
| 694 | azx_dev->index, sd_status);
|
| 695 | }
|
| 696 | if ((!azx_dev->substream && !azx_dev->cstream) ||
|
| 697 | !azx_dev->running || !(sd_status & SD_INT_COMPLETE))
|
| 698 | continue;
|
| 699 | if (ack)
|
| 700 | ack(bus, azx_dev);
|
| 701 | }
|
| 702 | }
|
| 703 | return handled;
|
| 704 | }
|
| 705 | EXPORT_SYMBOL_GPL(snd_hdac_bus_handle_stream_irq);
|
| 706 |
|
| 707 | |
| 708 | * snd_hdac_bus_alloc_stream_pages - allocate BDL and other buffers
|
| 709 | * @bus: HD-audio core bus
|
| 710 | *
|
| 711 | * Call this after assigning the all streams.
|
| 712 | * Returns zero for success, or a negative error code.
|
| 713 |
|
| 714 | int snd_hdac_bus_alloc_stream_pages(struct hdac_bus *bus)
|
| 715 | {
|
| 716 | struct hdac_stream *s;
|
| 717 | int num_streams = 0;
|
| 718 | int dma_type = bus->dma_type ? bus->dma_type : SNDRV_DMA_TYPE_DEV;
|
| 719 | int err;
|
| 720 |
|
| 721 | list_for_each_entry(s, &bus->stream_list, list) {
|
| 722 |
|
| 723 | err = snd_dma_alloc_pages(dma_type, bus->dev,
|
| 724 | BDL_SIZE, &s->bdl);
|
| 725 | num_streams++;
|
| 726 | if (err < 0)
|
| 727 | goto error_bdl;
|
| 728 | }
|
| 729 |
|
| 730 | if (WARN_ON(!num_streams))
|
| 731 | return -EINVAL;
|
| 732 |
|
| 733 | err = snd_dma_alloc_pages(dma_type, bus->dev,
|
| 734 | num_streams * 8, &bus->posbuf);
|
| 735 | if (err < 0)
|
| 736 | goto error_bdl;
|
| 737 | list_for_each_entry(s, &bus->stream_list, list)
|
| 738 | s->posbuf = (__le32 *)(bus->posbuf.area + s->index * 8);
|
| 739 |
|
| 740 |
|
| 741 | err = snd_dma_alloc_pages(dma_type, bus->dev, PAGE_SIZE, &bus->rb);
|
| 742 | if (err < 0)
|
| 743 | goto error_posbuf;
|
| 744 | return 0;
|
| 745 |
|
| 746 | error_posbuf:
|
| 747 | snd_dma_free_pages(&bus->posbuf);
|
| 748 | error_bdl:
|
| 749 | list_for_each_entry(s, &bus->stream_list, list) {
|
| 750 | if (s->bdl.area)
|
| 751 | snd_dma_free_pages(&s->bdl);
|
| 752 | }
|
| 753 | return -ENOMEM;
|
| 754 | }
|
| 755 | EXPORT_SYMBOL_GPL(snd_hdac_bus_alloc_stream_pages);
|
| 756 |
|
| 757 | |
| 758 | * snd_hdac_bus_free_stream_pages - release BDL and other buffers
|
| 759 | * @bus: HD-audio core bus
|
| 760 |
|
| 761 | void snd_hdac_bus_free_stream_pages(struct hdac_bus *bus)
|
| 762 | {
|
| 763 | struct hdac_stream *s;
|
| 764 |
|
| 765 | list_for_each_entry(s, &bus->stream_list, list) {
|
| 766 | if (s->bdl.area)
|
| 767 | snd_dma_free_pages(&s->bdl);
|
| 768 | }
|
| 769 |
|
| 770 | if (bus->rb.area)
|
| 771 | snd_dma_free_pages(&bus->rb);
|
| 772 | if (bus->posbuf.area)
|
| 773 | snd_dma_free_pages(&bus->posbuf);
|
| 774 | }
|
| 775 | EXPORT_SYMBOL_GPL(snd_hdac_bus_free_stream_pages);
|
| 776 |
|
| 777 | |
| 778 | * snd_hdac_bus_link_power - power up/down codec link
|
| 779 | * @codec: HD-audio device
|
| 780 | * @enable: whether to power-up the link
|
| 781 |
|
| 782 | void snd_hdac_bus_link_power(struct hdac_device *codec, bool enable)
|
| 783 | {
|
| 784 | if (enable)
|
| 785 | set_bit(codec->addr, &codec->bus->codec_powered);
|
| 786 | else
|
| 787 | clear_bit(codec->addr, &codec->bus->codec_powered);
|
| 788 | }
|
| 789 | EXPORT_SYMBOL_GPL(snd_hdac_bus_link_power);
|