/*
 * File: HdaRegisters.h
 *
 * Copyright (c) 2018 John Davis
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#ifndef _EFI_HDA_REGS_H__
#define _EFI_HDA_REGS_H__

#include <Uefi.h>

//
// Global Capabilities, Status, and Control.
//
// Global Capabilities; 2 bytes.
#define HDA_REG_GCAP            0x00
#define HDA_REG_GCAP_64OK       BIT0
#define HDA_REG_GCAP_NSDO(a)    ((UINT8)((a >> 1) & 0x3))
#define HDA_REG_GCAP_BSS(a)     ((UINT8)((a >> 3) & 0x1F))
#define HDA_REG_GCAP_ISS(a)     ((UINT8)((a >> 8) & 0xF))
#define HDA_REG_GCAP_OSS(a)     ((UINT8)((a >> 12) & 0xF))

// Minor Version; 1 byte.
#define HDA_REG_VMIN        0x02

// Major Version; 1 byte.
#define HDA_REG_VMAJ        0x03

// Output Payload Capability; 2 bytes.
#define HDA_REG_OUTPAY      0x04

// Input Payload Capability; 2 bytes.
#define HDA_REG_INPAY       0x06

// Global Control; 4 bytes.
#define HDA_REG_GCTL        0x08
#define HDA_REG_GCTL_CRST   BIT0
#define HDA_REG_GCTL_FCNTRL BIT1
#define HDA_REG_GCTL_UNSOL  BIT8

// Wake Enable; 2 bytes.
#define HDA_REG_WAKEEN  0x0C

// State Change Status; 2 bytes.
#define HDA_REG_STATESTS            0x0E
#define HDA_REG_STATESTS_INDEX(i)   ((UINT16)(1 << (i)))
#define HDA_REG_STATESTS_CLEAR      0xEFFF

// Global Status; 2 bytes
#define HDA_REG_GSTS        0x10
#define HDA_REG_GSTS_FSTS   BIT1

// Output Stream Payload Capability; 2 bytes.
#define HDA_REG_OUTSTRMPAY  0x18

// Input Stream Payload Capability; 2 bytes.
#define HDA_REG_INSTRMPAY   0x1A

//
// Interrupt Status and Control.
//
// Interrupt Control; 4 bytes.
#define HDA_REG_INTCTL      0x20

// Interrupt Status; 4 bytes.
#define HDA_REG_INTSTS      0x24

// Wall Clock Counter; 4 bytes.
#define HDA_REG_WALLCLOCK   0x30

// Stream Synchronization; 4 bytes.
#define HDA_REG_SSYNC       0x38

// CORB Lower Base Address; 4 bytes.
#define HDA_REG_CORBLBASE   0x40

// CORB Upper Base Address; 4 bytes.
#define HDA_REG_CORBUBASE   0x44

// CORB Write Pointer; 2 bytes.
#define HDA_REG_CORBWP      0x48

// CORB Read Pointer; 2 bytes.
#define HDA_REG_CORBRP          0x4A
#define HDA_REG_CORBRP_RP(a)    ((UINT8)a)
#define HDA_REG_CORBRP_RST      BIT15

// CORB Control; 1 byte.
#define HDA_REG_CORBCTL         0x4C
#define HDA_REG_CORBCTL_CMEIE   BIT0
#define HDA_REG_CORBCTL_CORBRUN BIT1

// CORB Status; 1 byte.
#define HDA_REG_CORBSTS         0x4D
#define HDA_REG_CORBSTS_CMEI    BIT0

// CORB Size; 1 byte.
#define HDA_REG_CORBSIZE                0x4E
#define HDA_REG_CORBSIZE_MASK           (BIT0 | BIT1)
#define HDA_REG_CORBSIZE_ENT2           0    // 8 B = 2 entries.
#define HDA_REG_CORBSIZE_ENT16          BIT0 // 64 B = 16 entries.
#define HDA_REG_CORBSIZE_ENT256         BIT1 // 1 KB = 256 entries.
#define HDA_REG_CORBSIZE_CORBSZCAP_2    BIT4 // 8 B = 2 entries.
#define HDA_REG_CORBSIZE_CORBSZCAP_16   BIT5 // 64 B = 16 entries.
#define HDA_REG_CORBSIZE_CORBSZCAP_256  BIT6 // 1 KB = 256 entries.

// RIRB Lower Base Address; 4 bytes.
#define HDA_REG_RIRBLBASE   0x50

// RIRB Upper Base Address; 4 bytes.
#define HDA_REG_RIRBUBASE   0x54

// RIRB Write Pointer; 2 bytes.
#define HDA_REG_RIRBWP          0x58
#define HDA_REG_RIRBWP_WP(a)    ((UINT8)a)
#define HDA_REG_RIRBWP_RST      BIT15

// Response Interrupt Count; 2 bytes.
#define HDA_REG_RINTCNT     0x5A

// RIRB Control; 1 byte.
#define HDA_REG_RIRBCTL             0x5C
#define HDA_REG_RIRBCTL_RINTCTL     BIT0
#define HDA_REG_RIRBCTL_RIRBDMAEN   BIT1
#define HDA_REG_RIRBCTL_RIRBOIC     BIT2

// RIRB Status; 1 byte.
#define HDA_REG_RIRBSTS         0x5D
#define HDA_REG_RIRBSTS_RINTFL  BIT0
#define HDA_REG_RIRBSTS_RIRBOIS BIT2

// RIRB Size; 1 byte.
#define HDA_REG_RIRBSIZE                0x5E
#define HDA_REG_RIRBSIZE_MASK           (BIT0 | BIT1)
#define HDA_REG_RIRBSIZE_ENT2           0    // 16 B = 2 entries.
#define HDA_REG_RIRBSIZE_ENT16          BIT0 // 128 B = 16 entries.
#define HDA_REG_RIRBSIZE_ENT256         BIT1 // 2 KB = 256 entries.
#define HDA_REG_RIRBSIZE_RIRBSZCAP_2    BIT4 // 16 B = 2 entries.
#define HDA_REG_RIRBSIZE_RIRBSZCAP_16   BIT5 // 128 B = 16 entries.
#define HDA_REG_RIRBSIZE_RIRBSZCAP_256  BIT6 // 2 KB = 256 entries.

// DMA Position Lower Base Address; 4 bytes.
#define HDA_REG_DPLBASE         0x70
#define HDA_REG_DPLBASE_EN      BIT0

// DMA Position Upper Base Address; 4 bytes.
#define HDA_REG_DPUBASE         0x74

//
// Immediate Command Input and Output Registers.
//
// Immediate Command Output Interface; 4 bytes.
#define HDA_REG_ICOI        0x60

// Immediate Command Input Interface; 4 bytes.
#define HDA_REG_ICII        0x64

// Immediate Command Status; 2 bytes.
#define HDA_REG_ICIS            0x68
#define HDA_REG_ICIS_ICB        BIT0
#define HDA_REG_ICIS_IRV        BIT1
#define HDA_REG_ICIS_ICV        BIT2
#define HDA_REG_ICIS_IRRUNSOL   BIT3
#define HDA_REG_ICIS_IRRADD(a)  ((UINT8)((a >> 4) & 0xF))

//
// Stream Descriptors.
//
// Input/Output/Bidirectional Stream Descriptor n Control; 3 bytes.
// Byte 1.
#define HDA_REG_SDNCTL1(n)      (0x80 + (0x20 * (n)))
#define HDA_REG_SDNCTL1_SRST    BIT0
#define HDA_REG_SDNCTL1_RUN     BIT1
#define HDA_REG_SDNCTL1_IOCE    BIT2
#define HDA_REG_SDNCTL1_FEIE    BIT3
#define HDA_REG_SDNCTL1_DEIE    BIT4

// Byte 2.
#define HDA_REG_SDNCTL2(n)      (0x81 + (0x20 * (n)))

// Byte 3.
#define HDA_REG_SDNCTL3(n)              (0x82 + (0x20 * (n)))
#define HDA_REG_SDNCTL3_TP              BIT2
#define HDA_REG_SDNCTL3_DIR             BIT3
#define HDA_REG_SDNCTL3_STRM_GET(a)     ((UINT8)((a >> 4) & 0xF))
#define HDA_REG_SDNCTL3_STRM_SET(a, s) ((UINT8)(((a) & 0x0F) | (((s) & 0xF)) << 4))

// Input/Output/Bidirectional Stream Descriptor n Status; 1 byte.
#define HDA_REG_SDNSTS(n)       (0x83 + (0x20 * (n)))
#define HDA_REG_SDNSTS_BCIS     BIT2
#define HDA_REG_SDNSTS_FIFOE    BIT3
#define HDA_REG_SDNSTS_DESE     BIT4
#define HDA_REG_SDNSTS_FIFORDY  BIT5

// Input/Output/Bidirectional Stream Descriptor n Link Position in Buffer; 4 bytes.
#define HDA_REG_SDNLPIB(n)      (0x84 + (0x20 * (n)))

// Input/Output/Bidirectional Stream Descriptor n Cyclic Buffer Length; 4 bytes.
#define HDA_REG_SDNCBL(n)       (0x88 + (0x20 * (n)))

// Input/Output/Bidirectional Stream Descriptor n Last Valid Index; 2 bytes.
#define HDA_REG_SDNLVI(n)       (0x8C + (0x20 * (n)))

// Input/Output/Bidirectional Stream Descriptor n FIFO Size; 2 bytes.
#define HDA_REG_SDNFIFOS(n)     (0x90 + (0x20 * (n)))

// Input/Output/Bidirectional Stream Descriptor n Format; 2 bytes.
#define HDA_REG_SDNFMT(n)           (0x92 + (0x20 * (n)))
#define HDA_REG_SDNFMT_CHAN(a)      ((UINT8)((a) & 0xF))
#define HDA_REG_SDNFMT_BITS(a)      ((UINT8)(((a) >> 4) & 0x3))
#define HDA_REG_SDNFMT_BITS_8       0x0
#define HDA_REG_SDNFMT_BITS_16      0x1
#define HDA_REG_SDNFMT_BITS_20      0x2
#define HDA_REG_SDNFMT_BITS_24      0x3
#define HDA_REG_SDNFMT_BITS_32      0x4
#define HDA_REG_SDNFMT_DIV(a)       ((UINT8)(((a) >> 8) & 0x3))
#define HDA_REG_SDNFMT_MULT(a)      ((UINT8)(((a) >> 11) & 0x3))
#define HDA_REG_SDNFMT_BASE_44KHZ   BIT14
#define HDA_REG_SDNFMT_SET(chan, bits, div, mult, base) \
    ((UINT16)(((chan) & 0xF) | (((bits) & 0x3) << 4) | (((div) & 0x3) << 8) | \
    (((mult) & 0x3) << 11) | ((base) ? HDA_REG_SDNFMT_BASE_44KHZ : 0)))

// Input/Output/Bidirectional Stream Descriptor n BDL Pointer Lower Base Address; 4 bytes.
#define HDA_REG_SDNBDPL(n)      (0x98 + (0x20 * (n)))

// Input/Output/Bidirectional Stream Descriptor n BDL Pointer Upper Base Address; 4 bytes.
#define HDA_REG_SDNBDPU(n)      (0x9C + (0x20 * (n)))

// Wall Clock Counter Alias; 4 bytes.
#define HDA_REG_WALCLKA         0x2030

// Input/Output/Bidirectional Stream Descriptor n Link Position in Buffer Alias; 4 bytes.
#define HDA_REG_SDNLPIBA(n)     (0x2084 + (0x20 * (n)))

#endif
