Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 7978d1e7 in mainline


Ignore:
Timestamp:
2014-08-14T08:56:27Z (6 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
master
Children:
8d070710
Parents:
b229062
Message:

Initialize CORB and RIRB.

Location:
uspace/drv/audio/hdaudio
Files:
1 added
5 edited
1 moved

Legend:

Unmodified
Added
Removed
  • uspace/drv/audio/hdaudio/hdactl.c

    rb229062 r7978d1e7  
    3333 */
    3434
     35#include <as.h>
     36#include <async.h>
     37#include <bitops.h>
    3538#include <ddf/log.h>
     39#include <ddi.h>
     40#include <errno.h>
     41#include <macros.h>
    3642#include <stdint.h>
    3743
    3844#include "hdactl.h"
    3945#include "regif.h"
    40 #include "hdaudio_regs.h"
     46#include "spec/regs.h"
     47
     48enum {
     49        ctrl_init_wait_max = 10,
     50        codec_enum_wait_us = 512
     51};
     52
     53/** Select an appropriate CORB/RIRB size.
     54 *
     55 * We always use the largest available size. In @a sizecap each of bits
     56 * 0, 1, 2 determine whether one of the supported size (0 == 2 enries,
     57 * 1 == 16 entries, 2 == 256 entries) is supported. @a *selsz is set to
     58 * one of 0, 1, 2 on success.
     59 *
     60 * @param sizecap       CORB/RIRB Size Capability
     61 * @param selsz         Place to store CORB/RIRB Size
     62 * @return              EOK on success, EINVAL if sizecap has no valid bits set
     63 *
     64 */
     65static int hda_rb_size_select(uint8_t sizecap, uint8_t *selsz)
     66{
     67        int i;
     68
     69        for (i = 2; i >= 0; --i) {
     70                if ((sizecap & BIT_V(uint8_t, i)) != 0) {
     71                        *selsz = i;
     72                        return EOK;
     73                }
     74        }
     75
     76        return EINVAL;
     77}
     78
     79static size_t hda_rb_entries(uint8_t selsz)
     80{
     81        switch (selsz) {
     82        case 0:
     83                return 2;
     84        case 1:
     85                return 16;
     86        case 2:
     87                return 256;
     88        default:
     89                assert(false);
     90                return 0;
     91        }
     92}
     93
     94/** Initialize the CORB */
     95static int hda_corb_init(hda_t *hda)
     96{
     97        uint8_t ctl;
     98        uint8_t corbsz;
     99        uint8_t sizecap;
     100        uint8_t selsz;
     101        bool ok64bit;
     102        int rc;
     103
     104        ddf_msg(LVL_NOTE, "hda_corb_init()");
     105
     106        /* Stop CORB if not stopped. */
     107        ctl = hda_reg8_read(&hda->regs->corbctl);
     108        if ((ctl & BIT_V(uint8_t, corbctl_run)) != 0) {
     109                ddf_msg(LVL_NOTE, "CORB is enabled, disabling first.");
     110                hda_reg8_write(&hda->regs->corbctl, ctl & ~BIT_V(uint8_t,
     111                    corbctl_run));
     112        }
     113
     114        /* Determine CORB size and allocate CORB buffer */
     115        corbsz = hda_reg8_read(&hda->regs->corbsize);
     116        sizecap = BIT_RANGE_EXTRACT(uint8_t, corbsize_cap_h,
     117            corbsize_cap_l, corbsz);
     118        rc = hda_rb_size_select(sizecap, &selsz);
     119        if (rc != EOK) {
     120                ddf_msg(LVL_ERROR, "Invalid CORB Size Capability");
     121                goto error;
     122        }
     123        corbsz = corbsz & ~BIT_RANGE(uint8_t, corbsize_size_h, corbsize_size_l);
     124        corbsz = corbsz | selsz;
     125
     126        ddf_msg(LVL_NOTE, "Setting CORB Size register to 0x%x", corbsz);
     127        hda_reg8_write(&hda->regs->corbsize, corbsz);
     128        hda->ctl->corb_entries = hda_rb_entries(selsz);
     129
     130        ddf_msg(LVL_NOTE, "Read GCAP");
     131        uint16_t gcap = hda_reg16_read(&hda->regs->gcap);
     132        ok64bit = (gcap & BIT_V(uint8_t, gcap_64ok)) != 0;
     133        ddf_msg(LVL_NOTE, "GCAP: 0x%x (64OK=%d)", gcap, ok64bit);
     134
     135        /*
     136         * CORB must be aligned to 128 bytes. If 64OK is not set,
     137         * it must be within the 32-bit address space.
     138         */
     139        hda->ctl->corb_virt = AS_AREA_ANY;
     140        rc = dmamem_map_anonymous(hda->ctl->corb_entries * sizeof(uint32_t),
     141            ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE, 0,
     142            &hda->ctl->corb_phys, &hda->ctl->corb_virt);
     143
     144        ddf_msg(LVL_NOTE, "Set CORB base registers");
     145
     146        /* Update CORB base registers */
     147        hda_reg32_write(&hda->regs->corblbase, LOWER32(hda->ctl->corb_phys));
     148        hda_reg32_write(&hda->regs->corbubase, UPPER32(hda->ctl->corb_phys));
     149
     150        ddf_msg(LVL_NOTE, "Rset CORB Read/Write pointers");
     151
     152        /* Reset CORB Read Pointer */
     153        hda_reg16_write(&hda->regs->corbrp, BIT_V(uint16_t, corbrp_rst));
     154
     155        /* Reset CORB Write Poitner */
     156        hda_reg16_write(&hda->regs->corbwp, 0);
     157
     158        ddf_msg(LVL_NOTE, "CORB initialized");
     159        return EOK;
     160error:
     161        return EIO;
     162}
     163
     164/** Initialize the RIRB */
     165static int hda_rirb_init(hda_t *hda)
     166{
     167        uint8_t ctl;
     168        uint8_t rirbsz;
     169        uint8_t sizecap;
     170        uint8_t selsz;
     171        bool ok64bit;
     172        int rc;
     173
     174        ddf_msg(LVL_NOTE, "hda_rirb_init()");
     175
     176        /* Stop RIRB if not stopped. */
     177        ctl = hda_reg8_read(&hda->regs->rirbctl);
     178        if ((ctl & BIT_V(uint8_t, rirbctl_run)) != 0) {
     179                ddf_msg(LVL_NOTE, "RIRB is enabled, disabling first.");
     180                hda_reg8_write(&hda->regs->corbctl, ctl & ~BIT_V(uint8_t,
     181                    rirbctl_run));
     182        }
     183
     184        /* Determine RIRB size and allocate RIRB buffer */
     185        rirbsz = hda_reg8_read(&hda->regs->rirbsize);
     186        sizecap = BIT_RANGE_EXTRACT(uint8_t, rirbsize_cap_h,
     187            rirbsize_cap_l, rirbsz);
     188        rc = hda_rb_size_select(sizecap, &selsz);
     189        if (rc != EOK) {
     190                ddf_msg(LVL_ERROR, "Invalid RIRB Size Capability");
     191                goto error;
     192        }
     193        rirbsz = rirbsz & ~BIT_RANGE(uint8_t, rirbsize_size_h, rirbsize_size_l);
     194        rirbsz = rirbsz | selsz;
     195
     196        ddf_msg(LVL_NOTE, "Setting RIRB Size register to 0x%x", rirbsz);
     197        hda_reg8_write(&hda->regs->rirbsize, rirbsz);
     198        hda->ctl->rirb_entries = hda_rb_entries(selsz);
     199
     200        ddf_msg(LVL_NOTE, "Read GCAP");
     201        uint16_t gcap = hda_reg16_read(&hda->regs->gcap);
     202        ok64bit = (gcap & BIT_V(uint8_t, gcap_64ok)) != 0;
     203        ddf_msg(LVL_NOTE, "GCAP: 0x%x (64OK=%d)", gcap, ok64bit);
     204
     205        /*
     206         * RIRB must be aligned to 128 bytes. If 64OK is not set,
     207         * it must be within the 32-bit address space.
     208         */
     209        hda->ctl->rirb_virt = AS_AREA_ANY;
     210        rc = dmamem_map_anonymous(hda->ctl->rirb_entries * sizeof(uint64_t),
     211            ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE, 0,
     212            &hda->ctl->rirb_phys, &hda->ctl->rirb_virt);
     213
     214        ddf_msg(LVL_NOTE, "Set RIRB base registers");
     215
     216        /* Update RIRB base registers */
     217        hda_reg32_write(&hda->regs->rirblbase, LOWER32(hda->ctl->rirb_phys));
     218        hda_reg32_write(&hda->regs->rirbubase, UPPER32(hda->ctl->rirb_phys));
     219
     220        ddf_msg(LVL_NOTE, "Rset RIRB Write pointer");
     221
     222        /* Reset RIRB Write Pointer */
     223        hda_reg16_write(&hda->regs->rirbwp, BIT_V(uint16_t, rirbwp_rst));
     224
     225        ddf_msg(LVL_NOTE, "RIRB initialized");
     226        return EOK;
     227error:
     228        return EIO;
     229}
    41230
    42231hda_ctl_t *hda_ctl_init(hda_t *hda)
    43232{
    44233        hda_ctl_t *ctl;
     234        uint32_t gctl;
     235        int cnt;
     236        int rc;
    45237
    46238        ctl = calloc(1, sizeof(hda_ctl_t));
     
    48240                return NULL;
    49241
     242        hda->ctl = ctl;
     243
    50244        uint8_t vmaj = hda_reg8_read(&hda->regs->vmaj);
    51245        uint8_t vmin = hda_reg8_read(&hda->regs->vmin);
     
    58252        }
    59253
     254        ddf_msg(LVL_NOTE, "reg 0x%zx STATESTS = 0x%x",
     255            (void *)&hda->regs->statests - (void *)hda->regs, hda_reg16_read(&hda->regs->statests));
     256
     257        gctl = hda_reg32_read(&hda->regs->gctl);
     258        if ((gctl & BIT_V(uint32_t, gctl_crst)) != 0) {
     259                ddf_msg(LVL_NOTE, "Controller not in reset. Resetting.");
     260                hda_reg32_write(&hda->regs->gctl, gctl & ~BIT_V(uint32_t, gctl_crst));
     261        }
     262
     263        ddf_msg(LVL_NOTE, "Taking controller out of reset.");
     264        hda_reg32_write(&hda->regs->gctl, gctl | BIT_V(uint32_t, gctl_crst));
     265
     266        /* Wait for CRST to read as 1 */
     267        cnt = ctrl_init_wait_max;
     268        while (cnt > 0) {
     269                gctl = hda_reg32_read(&hda->regs->gctl);
     270                if ((gctl & BIT_V(uint32_t, gctl_crst)) != 0) {
     271                        ddf_msg(LVL_NOTE, "gctl=0x%x", gctl);
     272                        break;
     273                }
     274
     275                ddf_msg(LVL_NOTE, "Waiting for controller to initialize.");
     276                async_usleep(100*1000);
     277                --cnt;
     278        }
     279
     280        if (cnt == 0) {
     281                ddf_msg(LVL_ERROR, "Timed out waiting for controller to come up.");
     282                goto error;
     283        }
     284
     285        ddf_msg(LVL_NOTE, "Controller is out of reset.");
     286
     287        /* Give codecs enough time to enumerate themselves */
     288        async_usleep(codec_enum_wait_us);
     289
     290        ddf_msg(LVL_NOTE, "STATESTS = 0x%x",
     291            hda_reg16_read(&hda->regs->statests));
     292
     293        rc = hda_corb_init(hda);
     294        if (rc != EOK)
     295                goto error;
     296
     297        rc = hda_rirb_init(hda);
     298        if (rc != EOK)
     299                goto error;
     300
    60301        return ctl;
    61302error:
    62303        free(ctl);
     304        hda->ctl = NULL;
    63305        return NULL;
    64306}
  • uspace/drv/audio/hdaudio/hdactl.h

    rb229062 r7978d1e7  
    3939
    4040typedef struct hda_ctl {
    41        
     41        uintptr_t corb_phys;
     42        void *corb_virt;
     43        size_t corb_entries;
     44
     45        uintptr_t rirb_phys;
     46        void *rirb_virt;
     47        size_t rirb_entries;
    4248} hda_ctl_t;
    4349
  • uspace/drv/audio/hdaudio/hdaudio.c

    rb229062 r7978d1e7  
    4444#include "hdactl.h"
    4545#include "hdaudio.h"
    46 #include "hdaudio_regs.h"
     46#include "spec/regs.h"
    4747
    4848#define NAME "hdaudio"
     
    7171        ddf_fun_t *fun_a;
    7272        hda_t *hda = NULL;
    73         const char *dev_name;
    7473        hw_res_list_parsed_t res;
    7574        void *regs;
    7675        int rc;
    7776
    78         dev_name = ddf_dev_get_name(dev);
    7977        ddf_msg(LVL_NOTE, "hda_dev_add()");
    8078
     
    127125        hda->regs = (hda_regs_t *)regs;
    128126
    129         hda->ctl = hda_ctl_init(hda);
    130         if (hda->ctl == NULL) {
     127        if (hda_ctl_init(hda) == NULL) {
    131128                rc = EIO;
    132129                goto error;
     
    151148
    152149        ddf_fun_add_to_category(fun_a, "virtual");
    153 
    154         ddf_msg(LVL_DEBUG, "Device `%s' accepted.", dev_name);
    155150        return EOK;
    156151error:
  • uspace/drv/audio/hdaudio/hdaudio.h

    rb229062 r7978d1e7  
    3030 * @{
    3131 */
    32 /** @file High Definition Audio controller
     32/** @file High Definition Audio driver
    3333 */
    3434
     
    4040#include <stdint.h>
    4141
    42 #include "hdaudio_regs.h"
     42#include "spec/regs.h"
    4343
    44 /** High Definition Audio Controller */
     44/** High Definition Audio driver instance */
    4545typedef struct {
    4646        async_sess_t *parent_sess;
  • uspace/drv/audio/hdaudio/hdaudio.ma

    rb229062 r7978d1e7  
     110 pci/ven=1002&dev=4383
    1210 pci/ven=8086&dev=2668
  • uspace/drv/audio/hdaudio/spec/regs.h

    rb229062 r7978d1e7  
    3333 */
    3434
    35 #ifndef HDAUDIO_REGS_H
    36 #define HDAUDIO_REGS_H
     35#ifndef SPEC_REGS_H
     36#define SPEC_REGS_H
    3737
    3838#include <sys/types.h>
     
    100100        uint32_t walclk;
    101101        /** Reserved */
    102         uint32_t reserved4[4];
     102        uint8_t reserved4[4];
     103        /** Stream Synchronization */
     104        uint32_t ssync;
     105        /** Reserved */
     106        uint8_t reserved5[4];
    103107        /** CORB Lower Base Address */
    104108        uint32_t corblbase;
     
    116120        uint8_t corbsize;
    117121        /** Reserved */
    118         uint8_t reserved5[1];
     122        uint8_t reserved6[1];
    119123        /** RIRB Lower Base Address */
    120124        uint32_t rirblbase;
     
    132136        uint8_t rirbsize;
    133137        /** Reserved */
    134         uint8_t reserved6[1];
     138        uint8_t reserved7[1];
    135139        /** Immediate Command Output Interface */
    136140        uint32_t icoi;
     
    140144        uint32_t icis;
    141145        /** Reserved */
    142         uint8_t reserved7[6];
     146        uint8_t reserved8[6];
    143147        /** DMA Position Buffer Lower Base */
    144148        uint32_t dpiblbase;
     
    146150        uint32_t dpibubase;
    147151        /** Reserved */
    148         uint8_t reserved8[8];
     152        uint8_t reserved9[8];
    149153        /** Stream descriptor registers */
    150154        hda_sdesc_regs_t sdesc[64];
    151155        /** Fill up to 0x2030 */
    152         uint8_t reserved9[6064];
     156        uint8_t reserved10[6064];
    153157        /** Wall Clock Counter Alias */
    154158        uint32_t walclka;
     
    157161} hda_regs_t;
    158162
     163typedef enum {
     164        /** Number of Output Streams Supported (H) */
     165        gcap_oss_h = 15,
     166        /** Number of Output Streams Supported (L) */
     167        gcap_oss_l = 12,
     168        /** Number of Input Streams Supported (H) */
     169        gcap_iss_h = 11,
     170        /** Number of Input Streams Supported (L) */
     171        gcap_iss_l = 8,
     172        /** Number of Bidirectional Streams Supported (H) */
     173        gcap_bss_h = 7,
     174        /** Number of Bidirectional Streams Supported (L) */
     175        gcap_bss_l = 3,
     176        /** Number of Serial Data Out Signals (H) */
     177        gcap_nsdo_h = 2,
     178        /** Number of Serial Data Out Signals (H) */
     179        gcap_nsdo_l = 1,
     180        /** 64 Bit Address Supported */
     181        gcap_64ok = 0
     182} hda_gcap_bits_t;
     183
     184typedef enum {
     185        /** Accept Unsolicited Response Enable */
     186        gctl_unsol = 8,
     187        /** Flush Control */
     188        gctl_fcntrl = 1,
     189        /** Controller Reset */
     190        gctl_crst = 0
     191} hda_gctl_bits_t;
     192
     193typedef enum {
     194        /** CORB Read Pointer Reset */
     195        corbrp_rst = 15,
     196        /** CORB Read Pointer (H) */
     197        corbrp_rp_h = 7,
     198        /** CORB Read Pointer (L) */
     199        corbrp_rp_l = 0
     200} hda_corbrp_bits_t;
     201
     202typedef enum {
     203        /** Enable CORB DMA Engine */
     204        corbctl_run = 1,
     205        /** CORB Memory Error Interrupt Enable */
     206        corbctl_meie = 0
     207} hda_corbctl_bits_t;
     208
     209typedef enum {
     210        /** CORB Size Capability (H) */
     211        corbsize_cap_h = 7,
     212        /** CORB Size Capability (L) */
     213        corbsize_cap_l = 4,
     214        /** CORB Size (H) */
     215        corbsize_size_h = 1,
     216        /** CORB Size (L) */
     217        corbsize_size_l = 0
     218} hda_corbsize_bits_t;
     219
     220typedef enum {
     221        /** RIRB Write Pointer Reset */
     222        rirbwp_rst = 15,
     223        /** RIRB Write Pointer (H) */
     224        rirbwp_wp_h = 7,
     225        /** RIRB Write Pointer (L) */
     226        rirbrp_wp_l = 0
     227} hda_rirbwp_bits_t;
     228
     229typedef enum {
     230        /** Response Overrun Interrupt Control */
     231        rirbctl_oic = 2,
     232        /** RIRB DMA Enable */
     233        rirbctl_run = 1,
     234        /** CORB Memory Error Interrupt Enable */
     235        rirbctl_int = 0
     236} hda_rirbctl_bits_t;
     237
     238typedef enum {
     239        /** RIRB Size Capability (H) */
     240        rirbsize_cap_h = 7,
     241        /** RIRB Size Capability (L) */
     242        rirbsize_cap_l = 4,
     243        /** RIRB Size (H) */
     244        rirbsize_size_h = 1,
     245        /** RIRB Size (L) */
     246        rirbsize_size_l = 0
     247} hda_rirbsize_bits_t;
     248
    159249#endif
    160250
Note: See TracChangeset for help on using the changeset viewer.