Changeset 7978d1e7 in mainline for uspace/drv/audio/hdaudio/hdactl.c
- Timestamp:
- 2014-08-14T08:56:27Z (10 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 8d070710
- Parents:
- b229062
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/audio/hdaudio/hdactl.c
rb229062 r7978d1e7 33 33 */ 34 34 35 #include <as.h> 36 #include <async.h> 37 #include <bitops.h> 35 38 #include <ddf/log.h> 39 #include <ddi.h> 40 #include <errno.h> 41 #include <macros.h> 36 42 #include <stdint.h> 37 43 38 44 #include "hdactl.h" 39 45 #include "regif.h" 40 #include "hdaudio_regs.h" 46 #include "spec/regs.h" 47 48 enum { 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 */ 65 static 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 79 static 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 */ 95 static 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; 160 error: 161 return EIO; 162 } 163 164 /** Initialize the RIRB */ 165 static 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; 227 error: 228 return EIO; 229 } 41 230 42 231 hda_ctl_t *hda_ctl_init(hda_t *hda) 43 232 { 44 233 hda_ctl_t *ctl; 234 uint32_t gctl; 235 int cnt; 236 int rc; 45 237 46 238 ctl = calloc(1, sizeof(hda_ctl_t)); … … 48 240 return NULL; 49 241 242 hda->ctl = ctl; 243 50 244 uint8_t vmaj = hda_reg8_read(&hda->regs->vmaj); 51 245 uint8_t vmin = hda_reg8_read(&hda->regs->vmin); … … 58 252 } 59 253 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 60 301 return ctl; 61 302 error: 62 303 free(ctl); 304 hda->ctl = NULL; 63 305 return NULL; 64 306 }
Note:
See TracChangeset
for help on using the changeset viewer.