Changeset 7978d1e7 in mainline for uspace/drv/audio/hdaudio/hdactl.c


Ignore:
Timestamp:
2014-08-14T08:56:27Z (10 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
8d070710
Parents:
b229062
Message:

Initialize CORB and RIRB.

File:
1 edited

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}
Note: See TracChangeset for help on using the changeset viewer.